home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Core / Prefs.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  93.0 KB  |  3,138 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Prefs.cpp
  3.  
  4.     Contains:    Implementation for Preferences class.
  5.  
  6.     Owned by:    Ed Lai
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <29>      12/19/96    TJ        1611139 First Document after install Fails,
  13.                                     Localization Fix
  14.         <28>     12/2/96    EL        1390351: Add alert to cancelling updating
  15.                                     editor database dialog.
  16.         <27>      11/22/96    EL        1388414: if system editor folder is
  17.                                     missing, just create one.
  18.         <26>      11/19/96    EL        1602166: limit length of chain when
  19.                                     resolving aliases.
  20.         <25>      10/22/96    DH        1369514    • OpenDoc runs out of memory
  21.                                     updating prefs during a drag. Information
  22.                                     is now loaded into temp mem instead of app
  23.                                     heap space.
  24.         <24>      10/16/96    RA        1368050: WARNs fire more precisely
  25.         <23>     10/7/96    RA        De/ActivateFrontWindow for scanning dlg
  26.         <22>     10/4/96    EL        1343891: put editor for wrong CPU into
  27.                                     kODWrongCPUEditor name space. 1363389:
  28.                                     registerFileLibs only after complete
  29.                                     scanning of a directory.
  30.         <21>     9/23/96    JP        1370876: Moved aete caching code up a
  31.                                     routine
  32.         <20>     9/18/96    RA        1368050: Enable WARNs
  33.         <19>     9/17/96    RA        1368050: OpenDoc should ignore Category
  34.                                     user strings for OD-defined categories
  35.         <18>     9/13/96    EL        1386043: integerity of the cache file in
  36.                                     crash. 1386048: error writing to cache file
  37.                                     should not be reported as folder missing.
  38.         <17>     7/26/96    RA        1372498: We should register a folder
  39.                                     containing an shlb w/ CFM even if it
  40.                                     contains no nmaps
  41.         <16>     7/25/96    DH        Fixed Read_nmap_buffer so that it now
  42.                                     Reraises if there is an exception, instead
  43.                                     of eating it and causing an infinite loop.
  44.         <15>     6/27/96    EL        1363389: while resolving aliases, alias not
  45.                                     found => not on current volume => can be
  46.                                     removed.
  47.         <14>     6/27/96    TJ        When scanning folders check for special
  48.                                     editors type, and only register folders
  49.                                     that have CFM type.
  50.         <13>     6/25/96    EL        1210509: defer to a later version. 1362088:
  51.                                     Do not alert when in background.
  52.         <12>     6/24/96    RA        1358594: Binding crashes if OpenDoc prefs
  53.                                     file is locked, don't write if prefs is
  54.                                     locked.
  55.         <11>     6/22/96    EL        1210509: alert when two editors with same
  56.                                     nmap. 1218948: alert when deleting pref
  57.                                     file. 1356059: preserve size resource when
  58.                                     pref file deleted.
  59.         <10>      6/4/96    EL        1283131: Separate Alerts for bad alias in
  60.                                     editor folder and in library folder.
  61.          <9>     5/31/96    jpa        T10012: Added editor namespace
  62.                                     EditorPlatformSignature.
  63.          <8>     5/24/96    jpa        1213332: Force 68k alignment of persistent
  64.                                     structs.
  65.          <7>     5/23/96    RA        1330687: BndNSUtl should use
  66.                                     platformFile->read instead of FSRead
  67.          <6>     5/22/96    EL        #1263100: Allow dragging of dialog, pass
  68.                                     update event to other windows, visual
  69.                                     feedback in dialog after cancel.
  70.          <5>     5/17/96    EL        #1263100: When building nmap cache file,
  71.                                     show dialog with progress bar so it can be
  72.                                     canceled, and do not mount server while
  73.                                     resolving alias.
  74.          <4>      5/3/96    EL        1257565: Optimized speed of
  75.                                     LoadCacheRezData(from Jens). Use assignment
  76.                                     instead of ODBlockMove for short and long.
  77.                                     1333188 Do not use Hard-coded constant.
  78.          <3>      2/2/96    TJ        We only delete the prefrences if they are
  79.                                     older then the oldest version we can read.
  80.          <2>      1/5/96    JP        1308887: Fixed computation of language code
  81.                                     in GetAETEs
  82.          
  83.     To Do:
  84.         
  85.     In Progress:
  86.         
  87. */
  88.  
  89. #ifndef _EXCEPT_
  90. #include "Except.h"
  91. #endif
  92.  
  93. #ifndef _PREFS_
  94. #include "Prefs.h"
  95. #endif
  96.  
  97. #ifndef _PREFSDEF_
  98. #include "PrefsDef.h"
  99. #endif
  100.  
  101. // this is here only because error codes like kODErrCannotFindOpenDocLibrariesFolder,
  102. // which should be elsewhere, are needed.
  103. #ifndef _SHELLDEF_
  104. #include <ShellDef.h>
  105. #endif
  106.  
  107. #ifndef _PLFMFILE_
  108. #include "PlfmFile.h"
  109. #endif
  110.  
  111. #ifndef SOM_ODNameSpaceManager_xh
  112. #include "NmSpcMg.xh"
  113. #endif
  114.  
  115. #ifndef SOM_ODNameSpace_xh
  116. #include "NamSpac.xh"
  117. #endif
  118.  
  119. #ifndef SOM_ODObjectNameSpace_xh
  120. #include "ObjectNS.xh"
  121. #endif
  122.  
  123. #ifndef SOM_ODValueNameSpace_xh
  124. #include "ValueNS.xh"
  125. #endif
  126.  
  127. #ifndef SOM_ODDispatcher_xh
  128. #include <Disptch.xh>
  129. #endif
  130.  
  131. #ifndef _ODSESSN_
  132. #include "ODSessn.xh"
  133. #endif
  134.  
  135. #ifndef SOM_ODTypeList_xh
  136. #include "TypeList.xh"
  137. #endif
  138.  
  139. #ifndef SOM_ODTranslation_xh
  140. #include <Translt.xh>
  141. #endif
  142.  
  143. #ifndef SOM_ODWindowState_xh
  144. #include <WinStat.xh>
  145. #endif
  146.  
  147. #ifndef __SCRIPT__
  148. #include <Script.h>
  149. #endif
  150.  
  151. #ifndef _USERSRCM_
  152. #include "UseRsrcM.h"
  153. #endif
  154.  
  155. #ifndef __ERRORS__
  156. #include <Errors.h>
  157. #endif
  158.  
  159. #ifndef _STDDEFS_
  160. #include "StdDefs.xh"
  161. #endif
  162.  
  163. #ifndef _ITEXT_
  164. #include "IText.h"
  165. #endif
  166.  
  167. #ifndef _LINKLIST_
  168. #include "LinkList.h"
  169. #endif
  170.  
  171. #ifndef _PASCLSTR_
  172. #include "PasclStr.h"
  173. #endif
  174.  
  175. #ifndef _BNDNSUTL_
  176. #include "BndNSUtl.h"
  177. #endif
  178.  
  179. #ifndef _ISOSTR_
  180. #include "ISOStr.h"
  181. #endif
  182.  
  183. #ifndef _BARRAY_
  184. #include "BArray.h"
  185. #endif
  186.  
  187. #ifndef _ODUTILS_
  188. #include <ODUtils.h>
  189. #endif
  190.  
  191. #ifndef _DLOGUTIL_
  192. #include <DlogUtil.h>
  193. #endif
  194.  
  195. #ifndef __ALIASES__
  196. #include <Aliases.h>
  197. #endif
  198.  
  199. #ifndef _NMSPCUTL_
  200. #include <NmSpcUtl.h>
  201. #endif
  202.  
  203. #include <string.h>
  204.  
  205. #ifndef __RESOURCES__
  206. #include <Resources.h>
  207. #endif
  208.  
  209. #ifndef __FOLDERS__
  210. #include <Folders.h>
  211. #endif
  212.  
  213. #ifndef __FINDER__
  214. #include <Finder.h>        /* For kIsInvisible */
  215. #endif
  216.  
  217. #ifndef __CONTROLS__
  218. #include <Controls.h>    /* For kControlButtonPart */
  219. #endif
  220.  
  221. #ifndef __DIALOGS__
  222. #include <Dialogs.h>
  223. #endif
  224.  
  225. #ifndef _REGISTER_
  226. #include <RegisterFileLibs.h>
  227. #endif
  228.  
  229. #ifndef _MEMDEBG_
  230. #include <MemDebg.h>    /* Testing only */
  231. #endif
  232.  
  233. #ifndef SOM_ODStorageSystem_xh
  234. #include <ODStor.xh>
  235. #endif
  236.  
  237. #ifndef _TEMPOBJ_
  238. #include <TempObj.h>
  239. #endif
  240.  
  241. #ifndef __ASREGISTRY__
  242. #include <ASRegistry.h>
  243. #endif
  244.  
  245. #ifndef __CODEFRAGMENTS__
  246. #include <CodeFragments.h>
  247. #endif
  248.  
  249. #ifndef __DEVICES__
  250. #include <Devices.h>
  251. #endif
  252.  
  253. #ifndef __FILES__
  254. #include <Files.h>
  255. #endif
  256.  
  257. #ifndef _FINDOPENDOCFOLDER_
  258. #include "FindOpenDocFolder.h"
  259. #endif
  260.  
  261. #pragma segment Preferences
  262.  
  263.  
  264. #undef LOGGING
  265. #define LOGGING 0
  266.  
  267. //==============================================================================
  268. // Constants
  269. //==============================================================================
  270.  
  271. const ODULong        kNumExpectedParts = 10;
  272.  
  273. const ODULong        kMinResynchTime = 2 * 60;    // Only check folders every 2 seconds
  274.  
  275. /*    Following is the table of namespaces to be created by Prefs. The Editor Namespaces
  276.     are also cleared whenever we re-scan the Editors folders. */
  277.  
  278. struct NameSpaceSpec {
  279.     const char *name;
  280.     ODNSTypeSpec type;
  281. };
  282.  
  283. const kNPrefNameSpaces = 4;
  284.  
  285. static const NameSpaceSpec kPrefNameSpaces[kNPrefNameSpaces] = {
  286.         {kODSysPrefEditorKinds,        kODNSDataTypeODValue}
  287.         ,{kODSysPrefEditorCategories,kODNSDataTypeODValue}
  288.         ,{kODSysPrefContainerSuites,    kODNSDataTypeODValue}
  289.         ,{kODFileFromEditor,            kODNSDataTypeODValue}
  290.     };
  291.  
  292. const kNEditorNameSpaces = 11;
  293.  
  294. static const NameSpaceSpec kEditorNameSpaces[kNEditorNameSpaces] = {
  295.         {kODContainerSuite,            kODNSDataTypeODValue},    // From OD libraries (Bento)
  296.         {kODKind,                    kODNSDataTypeODObject},
  297.         {kODEditorKinds,            kODNSDataTypeODObject},
  298.         //{kODViewer,                    kODNSDataTypeODObject},
  299.         {kODViewer,                    kODNSDataTypeODValue},
  300.         //{kODEditorUserString,        kODNSDataTypeODObject},
  301.         //{kODKindUserString,            kODNSDataTypeODObject},
  302.         //{kODCategoryUserString,        kODNSDataTypeODObject},
  303.         {kODEditorUserString,        kODNSDataTypeODValue},
  304.         {kODKindUserString,            kODNSDataTypeODValue},
  305.         {kODCategoryUserString,        kODNSDataTypeODValue},
  306.         {kODKindOldMacOSType,        kODNSDataTypeODValue},
  307.         {kODEditorHelpFile,            kODNSDataTypeODValue},
  308.         {kODEditorPlatformSignature,kODNSDataTypeODValue},
  309.         {kODWrongCUPEditor,            kODNSDataTypeODValue}
  310.     };
  311.  
  312. const ODSShort kMaxDirDepth = 5;
  313. const ODUShort kMaxResolveCount = 10;
  314.  
  315. #define typeAECache 'aech'
  316.  
  317. //==============================================================================
  318. // Scalar Types
  319. //==============================================================================
  320.  
  321. #if PRAGMA_ALIGN_SUPPORTED
  322. #pragma options align=mac68k
  323. #endif
  324.  
  325. struct cfragHeader {
  326.     ODULong    reserved1;
  327.     ODULong    reserved2;
  328.     ODULong    version;
  329.     ODULong    reserved3;
  330.     ODULong    reserved4;
  331.     ODULong    reserved5;
  332.     ODULong    reserved6;
  333.     ODULong    numFragDescs;
  334. };
  335.  
  336. typedef cfragHeader cfragHeader;
  337.  
  338. struct cfragDescHeader {
  339.     ODULong    arch;
  340.     ODULong    updateLevel;
  341.     ODULong    currVersion;
  342.     ODULong    oldDefVer;
  343.     ODULong    appStackSize;
  344.     ODSShort    appLibDir;
  345.     ODSByte    fragType;
  346.     ODSByte    fragLoc;
  347.     ODULong    fragOffset;
  348.     ODULong    fragLen;
  349.     ODULong    reserved1;
  350.     ODULong    reserved2;
  351.     ODSShort    infoRecLen;
  352. };
  353.  
  354. struct cfragDescriptor {
  355.     cfragDescHeader header;
  356.     Str255            fragName;
  357. };
  358.  
  359. typedef cfragDescriptor cfragDescriptor;
  360.  
  361. #if PRAGMA_ALIGN_SUPPORTED
  362. #pragma options align=reset
  363. #endif
  364.  
  365. //==============================================================================
  366. // Global Variables
  367. //==============================================================================
  368.  
  369. //==============================================================================
  370. // Local Classes
  371. //==============================================================================
  372.  
  373. class PrefsDirInfo :public Link 
  374. {
  375. public:
  376.     PrefsDirType                fType;            // Type of folder
  377.     ODSShort                    fDepth;            // Nesting depth
  378.     short                        fVol;            // Volume refNum
  379.     long                        fDir;            // Directory ID
  380.     ODULong                        fModDate;        // Dir's mod date when last scanned
  381. };
  382.  
  383.  
  384. //==============================================================================
  385. // Function Prototype
  386. //==============================================================================
  387.  
  388. static ODBoolean GetIndVolume( short index, short *vRefNum );
  389. static ODSLong GetFldrDirID( FSSpec theFolderSpec, ODULong *modDate =kODNULL );
  390. static void GetDirModDateAndParent( short vol, long dir, ODULong *modDate, long *parent );
  391. static ODSize ExtractIText(ODSize bufferPos, ODSession* session, ODValueNameSpace*, ODISOStr key);
  392. static ODSize ExtractISOStringList(ODSize bufferPos, ODSession* session, ODObjectNameSpace*, ODISOStr key);
  393. static ODSize ExtractOSType(ODSize bufferPos, ODSession* session, ODValueNameSpace*, ODISOStr key);
  394. static ODSize ExtractPltfrmTypeSpac(ODSize bufferPos, ODSession* session, ODISOStr key);
  395. static ODSize ExtractISOString(ODSize bufferPos, ODSession* session, ODValueNameSpace*, ODISOStr key);
  396. static ODError FindMagicFolder( OSType folderType, ODBoolean createFolder, ConstStr255Param folderName,
  397.                              short *vol, long *dir, ODULong *modDate );
  398. static ODBoolean FindVolumeEditorsFolder( short vol, ConstStr255Param, FSSpec * );
  399. static ODSize ExtractHelpFileName(    ODSize bufferPos, 
  400.                                     ODSession* session, 
  401.                                     const ODFileSpec* fsspec,
  402.                                     ODValueNameSpace *theNameSpace, 
  403.                                     ODISOStr key);
  404. static void Cache_nmap( PlatformFile* cacheFile, ODISOStr nameSpaceName, ODSize bufferSize, 
  405.                                     Handle mappingPair, const FSSpec *fsspec );
  406. static void MoveToTrash( short vRefnum, long dirID, Str255 name );
  407. static void    Read_aete_Resources( FSSpec* fsspec, AEDescList* aetes );
  408. static void    AddAETEs(PlatformFile* cacheFile, ODSLong languageCode, AEDescList* aeteList);
  409. static ODBoolean GetODPrefsFolder(ODSShort* prefVol, ODSLong* prefDir );
  410. static OSErr ConstructCacheFileName(ODSShort fldrVRefNum, ODSLong fldrDirID, 
  411.                                       ODULong fldrModDate, Str255* fileName );
  412. static void DeleteOldCacheFiles();
  413. static ODBoolean LoadableLibrary(ODSShort resRefNum);
  414.  
  415. static OSErr ResolveLocalAliasFile(FSSpec *theSpec, Boolean resolveAliasChains, 
  416.                                     Boolean *targetIsFolder, Boolean *wasAliased);
  417.                                     
  418. //==============================================================================
  419. // Class Preferences
  420. //==============================================================================
  421.  
  422. //------------------------------------------------------------------------------
  423. // Preferences::Preferences
  424. //------------------------------------------------------------------------------
  425. Preferences::Preferences()
  426. {
  427.     fSession            = (ODSession*) kODNULL;
  428.     fNameSpaceMgr        = kODNULL;
  429.     fPrefsFile             = (PlatformFile*)kODNULL;
  430.     fPrefsModDate        = 0;
  431.     fDirList            = kODNULL;
  432.     fLastSynchedAt        = 0;
  433.     fPrevSizeRsrc        = kODNULL;
  434.     fScanning            = kODFalse;
  435.     fScanningDialog        = kODNULL;
  436.     fCacheFile            = kODNULL;
  437. }
  438.  
  439. //------------------------------------------------------------------------------
  440. // Preferences::~Preferences
  441. //------------------------------------------------------------------------------
  442. Preferences::~Preferences()
  443. {
  444.     ODDeleteObject( fPrefsFile );
  445.     if( fPrevSizeRsrc ) DisposeHandle( fPrevSizeRsrc );
  446.     if( fDirList ) {
  447.         fDirList->DeleteAllLinks();
  448.         delete fDirList;
  449.     }
  450.     WASSERT(fScanningDialog==kODNULL);
  451. }
  452.  
  453. //------------------------------------------------------------------------------
  454. // Preferences::InitPreferences
  455. //------------------------------------------------------------------------------
  456. void Preferences::InitPreferences(ODSession* session)
  457. {
  458.     ODSShort foundVRefNum;
  459.     ODSLong     foundDirID;
  460.     CInfoPBRec    info;
  461.     
  462.     if( LOGGING ) {
  463.         SetOutputMode(kWriteToDebugWindow);
  464.         LOG("~C");
  465.     }
  466.  
  467.     fSession = session;
  468.     fNameSpaceMgr = fSession->GetNameSpaceManager(somGetGlobalEnvironment());
  469.  
  470.     fDirList = new LinkedList;
  471.     
  472.     if ( FindOpenDocFolder(kOnSystemDisk, kOpenDocLibrariesFolderType, kDontCreateFolder, 
  473.             &foundVRefNum, &foundDirID) == noErr)
  474.         {
  475.             info.dirInfo.ioCompletion = nil;
  476.             info.dirInfo.ioVRefNum = foundVRefNum;
  477.             info.dirInfo.ioNamePtr = fLibsFolderName;
  478.             info.dirInfo.ioFDirIndex = -1;
  479.             info.dirInfo.ioDrDirID = foundDirID;
  480.             if (PBGetCatInfoSync(&info) != noErr)
  481.                 ODGetString(fLibsFolderName, kODLibsFldrNameStrID);
  482.  
  483.         }
  484.     else
  485.         ODGetString(fLibsFolderName, kODLibsFldrNameStrID);
  486.     
  487.     if ( FindOpenDocFolder(kOnSystemDisk, kOpenDocEditorsFolderType, kDontCreateFolder, 
  488.             &foundVRefNum, &foundDirID) == noErr)
  489.         {
  490.             info.dirInfo.ioCompletion = nil;
  491.             info.dirInfo.ioVRefNum = foundVRefNum;
  492.             info.dirInfo.ioNamePtr = fEditorsFolderName;
  493.             info.dirInfo.ioFDirIndex = -1;
  494.             info.dirInfo.ioDrDirID = foundDirID;
  495.             if (PBGetCatInfoSync(&info) != noErr)
  496.                 ODGetString(fEditorsFolderName,kODEditorsFldrNameStrID);
  497.  
  498.         }
  499.     else
  500.         ODGetString(fEditorsFolderName,kODEditorsFldrNameStrID);
  501.  
  502.         // Create the ContainerSuite, Kind and Category NameSpaces
  503.     CreatePrefsNameSpaces();
  504.  
  505.         // Initialize fPrefsFile and fPrefsfModDate
  506.     GetOpenDocPrefs();
  507.  
  508.     // Don't read the Libraries and Editors folders yet; be lazy about this,
  509.     // they'll be read when needed (ScanLibsAndEditors will be called.)
  510.     
  511.     DeleteOldCacheFiles();
  512. }
  513.  
  514. //------------------------------------------------------------------------------
  515. // Preferences::Purge
  516. //------------------------------------------------------------------------------
  517. ODSize Preferences::Purge(ODSize size)
  518. {
  519. ODUnused(size);
  520.     return 0; //this->ClearEditorNameSpaces();
  521. }
  522.  
  523. //------------------------------------------------------------------------------
  524. // Preferences::GetOpenDoc_nmaps
  525. //------------------------------------------------------------------------------
  526.  
  527. void Preferences::GetOpenDoc_nmaps()
  528. {
  529.     ODSShort libsVRefNum;
  530.     ODSLong libsDirID;
  531.     ODULong libsModDate;
  532.     
  533.         // Load any nmaps found in magic OpenDoc Libraries folder
  534.     if ( FindMagicFolder(kExtensionFolderType,kDontCreateFolder,fLibsFolderName,
  535.                         &libsVRefNum,&libsDirID,&libsModDate) != noErr)
  536.         THROW(kODErrCannotFindOpenDocLibrariesFolder);
  537.     
  538.     this->ScanDirectoryTree(libsVRefNum, libsDirID, libsModDate, kLibsFolder);
  539. }
  540.  
  541. //------------------------------------------------------------------------------
  542. // Preferences::CreateNameSpaces
  543. //------------------------------------------------------------------------------
  544.  
  545. void Preferences::CreatePrefsNameSpaces()
  546. {
  547.     // This creates the 3 namespaces loaded from Prefs and the container suites.
  548.     
  549.     Environment* ev = somGetGlobalEnvironment ();
  550.     for( ODSLong i=0; i<kNPrefNameSpaces; i++ )
  551.         fNameSpaceMgr->CreateNameSpace(ev, (ODISOStr)kPrefNameSpaces[i].name,
  552.                                            kODNULL,kNumExpectedParts,
  553.                                            kPrefNameSpaces[i].type);
  554. }
  555.  
  556. //------------------------------------------------------------------------------
  557. // Preferences::ClearEditorNameSpaces
  558. //------------------------------------------------------------------------------
  559.  
  560. ODSize Preferences::ClearEditorNameSpaces()
  561. {
  562.     // Clears the namespaces that store the info read from the Editors folders.
  563.     // The other three namespaces are read in from the Prefs file.
  564.  
  565.     size_t oldFreeSpace;
  566.     MMGetFreeSpace(kODNULL,&oldFreeSpace,kODNULL);
  567.     
  568.     Environment* ev = somGetGlobalEnvironment ();
  569.     for( ODSLong i=0; i<kNEditorNameSpaces; i++ ) {
  570.         ODNameSpace *ns = fNameSpaceMgr->HasNameSpace(ev, (ODISOStr)kEditorNameSpaces[i].name);
  571.         if( ns )
  572.             fNameSpaceMgr->DeleteNameSpace(ev,ns);
  573.         ns = fNameSpaceMgr->CreateNameSpace(ev, (ODISOStr)kEditorNameSpaces[i].name,
  574.                                            kODNULL,kNumExpectedParts,
  575.                                            kEditorNameSpaces[i].type);
  576.         ns->SetSynchedToEditors(ev,kODTrue);
  577.     }
  578.     
  579.     fDirList->DeleteAllLinks();
  580.     
  581.     size_t newFreeSpace;
  582.     MMGetFreeSpace(kODNULL,&newFreeSpace,kODNULL);
  583.     newFreeSpace -= oldFreeSpace;
  584.     if( (ODSLong)newFreeSpace < 0 )
  585.         newFreeSpace = 0;
  586.     return newFreeSpace;
  587. }
  588.  
  589.  
  590. //------------------------------------------------------------------------------
  591. // Preferences::ScanDirectoryTree
  592. //------------------------------------------------------------------------------
  593.  
  594. void Preferences::ScanDirectoryTree(ODSShort fldrVRefNum, ODSLong fldrDirID,
  595.                                     ODULong fldrModDate, PrefsDirType type)
  596. {
  597.     AEDescList        aetes = {typeNull, kODNULL};
  598.  
  599.     LinkedList* dirTreeList = new LinkedList;
  600.     PrefsDirInfo *last = kODNULL;
  601.     PlatformFile* cacheFile = new PlatformFile;
  602.     
  603.         // verify the nmap cache
  604.     ODBoolean cacheIsValid = kODFalse;
  605.     this->VerifyCache(fldrVRefNum, fldrDirID, fldrModDate, type,
  606.                                             &cacheFile, &dirTreeList, &cacheIsValid);
  607.     
  608.         // if the cache is valid, load the cached data
  609.     if ( cacheIsValid )
  610.         cacheIsValid = this->LoadCachedRezData(cacheFile, fldrVRefNum);
  611.         
  612.     if ( !cacheIsValid )
  613.     {
  614.         this->ShowScanningDialog(cacheFile);// Tell user we're updating the list
  615.         
  616.         // Create an empty list of aete resources
  617.         {
  618.             COverridingMacOSMemory foo;
  619.  
  620.             THROW_IF_ERROR( AECreateList(kODNULL, 0, kODFalse, &aetes) );
  621.         }
  622.  
  623.              // empty the list and start over
  624.         if (!dirTreeList->IsEmpty())
  625.             dirTreeList->RemoveAll();
  626.         
  627.             //    get current mod date of dir id
  628.         ODULong currentModDate;
  629.         long parent;
  630.         GetDirModDateAndParent(fldrVRefNum, fldrDirID, ¤tModDate, &parent);
  631.  
  632.             // add to local list of scanned directories
  633.         PrefsDirInfo *last = this->AddDirInfo(dirTreeList, fldrVRefNum,fldrDirID,
  634.                                                 currentModDate,1,type);
  635.  
  636.         ODSLong    sizeOfLong = sizeof( long );
  637.         ODULong    zero = 0;
  638.         
  639.         while( last ) {
  640.             this->TraverseDirectory(last->fVol,last->fDir, last->fDepth, dirTreeList);
  641.                 // write this directory id and mod date to cache file
  642.             if (cacheFile)
  643.             {
  644.                 cacheFile->Write( (ODSByte*) &last->fDir, &sizeOfLong );
  645.                 cacheFile->Write( (ODSByte*) &last->fModDate , &sizeOfLong );
  646.             }
  647.             last = (PrefsDirInfo*) dirTreeList->After((const Link&)*last);
  648.         }
  649.             // write out 0 to signify end of dir list in cache file
  650.         if (cacheFile)
  651.             cacheFile->Write( (ODSByte*) &zero, &sizeOfLong );
  652.  
  653.             // Loop through directory list loading nmaps and adding nmap data to cache
  654.         PrefsDirInfo *f;
  655.         for( f=(PrefsDirInfo*)dirTreeList->First(); f; 
  656.                                 f=(PrefsDirInfo*)dirTreeList->After(*f) ) 
  657.         {
  658.             this->ScanDirectory(f->fVol,f->fDir, cacheFile, &aetes);
  659.         }
  660.  
  661.         // save this aete list in the cachefile for this disk
  662.         ODSLong    n = 0;    
  663.         THROW_IF_ERROR( AECountItems(&aetes, &n) );
  664.         if (n != 0)
  665.         {
  666.             AEDesc    tempRec;
  667.             {
  668.                 COverridingMacOSMemory foo;
  669.     
  670.                 THROW_IF_ERROR( AECreateList(kODNULL, 0, kODTrue, &tempRec) );
  671.             }
  672.             THROW_IF_ERROR( AEPutKeyDesc(&tempRec, keyDirectObject, &aetes) );
  673.             ODLockHandle(tempRec.dataHandle);
  674.             WASSERT(cacheFile);
  675.             cacheFile->WriteResourcePtr(typeAECache, 0, *tempRec.dataHandle, GetHandleSize(tempRec.dataHandle));
  676.             THROW_IF_ERROR( AEDisposeDesc(&tempRec) );
  677.         };
  678.         THROW_IF_ERROR( AEDisposeDesc(&aetes) );
  679.     }
  680.     
  681.         // Add this local list to the end of fDirList
  682.     this->AddDirList( dirTreeList );
  683.  
  684.     if (!dirTreeList->IsEmpty())
  685.         dirTreeList->DeleteAllLinks();
  686.     ODDeleteObject( dirTreeList );
  687.  
  688.     if (cacheFile)
  689.     {
  690.         cacheFile->Close();
  691.         ODSByte pname[256];
  692.         cacheFile->GetAsciiName(pname, 255);
  693.         ODULong nameLen = ODISOStrLength(pname);
  694.         ODULong suffixLen = ODISOStrLength(kODCacheTempSuffix);
  695.         if ((nameLen > suffixLen) && ODISOStrEqual(&pname[nameLen-suffixLen], kODCacheTempSuffix)) {
  696.             // if name says it is temp, we remove the temp suffix to get the proper file name
  697.             // However the process of renaming would change the folder mod date, so it look
  698.             // like the folder has been changed. So we have to change name and then restore mod date
  699.             CInfoPBRec    pb;
  700.             memset (&pb,0,sizeof(pb));
  701.             pb.dirInfo.ioFDirIndex = -1;
  702.             pb.dirInfo.ioNamePtr = kODNULL;
  703.             pb.dirInfo.ioVRefNum = fldrVRefNum;
  704.             pb.dirInfo.ioDrDirID = fldrDirID;
  705.             ODError result = PBGetCatInfoSync((CInfoPBPtr)&pb);
  706.             pname[nameLen-suffixLen] = 0; // remove the suffix
  707.             cacheFile->Rename(CToPascalString(pname));
  708.             if ( !result )
  709.                 PBSetCatInfoSync((CInfoPBPtr)&pb);
  710.         }
  711.         ODDeleteObject( cacheFile );
  712.     }
  713. }
  714.  
  715. //------------------------------------------------------------------------------
  716. // Preferences::VerifyCache
  717. //------------------------------------------------------------------------------
  718.  
  719. void Preferences::VerifyCache(ODSShort fldrVRefNum, 
  720.                                   ODSLong fldrDirID, 
  721.                                   ODULong fldrModDate,
  722.                                   PrefsDirType type,
  723.                                   PlatformFile** cacheFile,
  724.                                   LinkedList** dirTreeList, 
  725.                                   ODBoolean* cacheIsValid)
  726. {
  727.     *cacheIsValid = kODTrue;
  728.     
  729.         // attempt to locate the fPrefsFile
  730.     if (!GetCacheFile(cacheFile, fldrVRefNum, fldrDirID, fldrModDate) || 
  731.         !LoadCachedDirList(*cacheFile, fldrVRefNum, dirTreeList, type))
  732.     {
  733.             // If a cache file is invalid or cannot be found
  734.             // attempt to delete an existing file if it exists
  735.         TRY{
  736.             if (*cacheFile && (*cacheFile)->Exists())
  737.                 (*cacheFile)->Delete();
  738.         }CATCH_ALL{
  739.             ODDeleteObject (*cacheFile);
  740.         }ENDTRY
  741.             
  742.             // attempt to create a new cache file
  743.         if (*cacheFile)
  744.         {
  745.             // to ensure that the file will not be used until we finish generating it
  746.             // we use a temp name and rename it to the proper name when we are done
  747.             ODSByte pname[64];
  748.             (*cacheFile)->GetAsciiName(pname, 63);
  749.             if ((ODISOStrLength(pname) + ODISOStrLength(kODCacheTempSuffix)) <= 63)
  750.             {
  751.                 ODISOStrConcat(pname,kODCacheTempSuffix);
  752.                 (*cacheFile)->SetAsciiName(pname);
  753.                 TRY
  754.                 if ((*cacheFile)->Exists())
  755.                     (*cacheFile)->Delete();
  756.                 CATCH_ALL
  757.                 ENDTRY
  758.             }
  759.             TRY{
  760.                 (*cacheFile)->Create(kODShellSignature, 
  761.                                     kPreferencesFolderType, 
  762.                                     smSystemScript );
  763.                                     
  764.             }CATCH_ALL{
  765.                 
  766.                 //CATCH(afpAccessDenied)
  767.                 //CATCH(wPrErr)
  768.                 //CATCH(vLckdErr)
  769.                 //CATCH(dskFulErr)
  770.  
  771.                     // if the cache file cannot be written to volume, create it in prefs
  772.                     // folder
  773.                 Str255 cacheName;
  774.                 ODSShort prefsVol;
  775.                 ODSLong prefsDir;
  776.                 ODFileSpec cacheFileSpec;
  777.  
  778.                 if(GetODPrefsFolder( &prefsVol, &prefsDir ))
  779.                 {
  780.                     OSErr result = ConstructCacheFileName( fldrVRefNum, 
  781.                         fldrDirID, fldrModDate, &cacheName );
  782.                     if (result == noErr)
  783.                     {
  784.                         result = FSMakeFSSpec(prefsVol, prefsDir, cacheName, &cacheFileSpec);
  785.                         if (result == fnfErr )
  786.                         {
  787.                             (*cacheFile)->Specify(&cacheFileSpec);
  788.                             
  789.                             TRY{
  790.                                 (*cacheFile)->Create(kODShellSignature, 
  791.                                                 kPreferencesFolderType, 
  792.                                                 smSystemScript );
  793.                             }CATCH_ALL{
  794.                                 WARN("Error creating cache file");
  795.                 if ((*cacheFile)->Exists())
  796.                     (*cacheFile)->Delete();
  797.                 ODDeleteObject (*cacheFile);
  798.             }ENDTRY
  799.         }
  800.                         else
  801.                             ODDeleteObject (*cacheFile);
  802.                     }
  803.                     else
  804.                         ODDeleteObject (*cacheFile);
  805.                 }
  806.                 else
  807.                     ODDeleteObject (*cacheFile);
  808.  
  809.             }ENDTRY
  810.  
  811.             if (*cacheFile)
  812.             {
  813.                 TRY{
  814.                         // After creating file, make it invisible:
  815.                 if (!LOGGING) /*  Don't make invisible if logging for testing purposes */
  816.                 {
  817.                     ODFileSpec fileSpec = (*cacheFile)->GetFileSpec();
  818.                     FInfo info;
  819.                     
  820.                     if( HGetFInfo(fldrVRefNum,fldrDirID,fileSpec.name,&info) == noErr ) {
  821.                         info.fdFlags |= kIsInvisible;
  822.                         HSetFInfo(fldrVRefNum,fldrDirID,fileSpec.name,&info);
  823.                     }
  824.                 }
  825.  
  826.                     (*cacheFile)->Open();
  827.                         // Position mark to beginning of file
  828.                     (*cacheFile)->SetFilePos(fsFromStart, 0);
  829.                     
  830.                 }CATCH_ALL{
  831.                     if ((*cacheFile)->Exists())
  832.                         (*cacheFile)->Delete();
  833.                     ODDeleteObject (*cacheFile);
  834.                 }ENDTRY
  835.             }
  836.         }
  837.             // indicate that cached data is not valid
  838.         *cacheIsValid = kODFalse;
  839.     }
  840. }
  841.  
  842. //------------------------------------------------------------------------------
  843. // Preferences::LoadCachedDirList
  844. //------------------------------------------------------------------------------
  845.  
  846. ODBoolean Preferences::LoadCachedDirList(PlatformFile* cacheFile,
  847.                                           ODSShort fldrVRefNum,
  848.                                           LinkedList** dirTreeList,
  849.                                           PrefsDirType type)
  850. {
  851.     ODBoolean cacheIsValid = kODFalse;
  852.     PrefsDirType flderType = type;
  853.     
  854.     if ((!cacheFile) || (!cacheFile->Exists()))
  855.         return cacheIsValid;
  856.     
  857.     TRY{
  858.         cacheFile->Open();
  859.             // Position mark to beginning of file
  860.         cacheFile->SetFilePos(fsFromStart, 0);
  861.         
  862.         for ( ODSLong fileOffset = 0; 
  863.               fileOffset != cacheFile->GetEndOfFile(); 
  864.               fileOffset = cacheFile->GetFilePos() ) 
  865.         {
  866.             ODULong dirID;
  867.             ODULong modDate;
  868.             ODSLong    sizeoflong = sizeof( long );
  869.             
  870.             //    read in a dir id
  871.             cacheFile->Read( (ODSByte*)&dirID, &sizeoflong );
  872.     
  873.                 //    if 0 is read in, end of cached dir list
  874.             if (dirID == 0)
  875.                 break;
  876.     
  877.                 // read in a modDate
  878.             cacheFile->Read( (ODSByte*)&modDate, &sizeoflong );
  879.     
  880.                 //    get current mod date of dir id
  881.             ODULong currentModDate;
  882.             long parent;
  883.             GetDirModDateAndParent(fldrVRefNum, dirID, ¤tModDate, &parent);
  884.     
  885.                 //    compare it with the one read in
  886.             if (modDate == currentModDate)
  887.             {
  888.                         //Add this dir to linked list
  889.                     PrefsDirInfo *last = kODNULL;
  890.                     last = this->AddDirInfo(*dirTreeList, fldrVRefNum,dirID,modDate,1,flderType );
  891.                     last = (PrefsDirInfo*) (*dirTreeList)->After(*last);
  892.                     flderType = kNestedFolder;
  893.                     cacheIsValid = kODTrue;
  894.             }
  895.             else
  896.             {
  897.                 cacheIsValid = kODFalse;
  898.                 break;
  899.             }
  900.         }
  901.  
  902.         if (!cacheIsValid)
  903.             cacheFile->Close();
  904.         else
  905.         {
  906.                 // Loop through directory list registering each dir with cfm
  907.             PrefsDirInfo *f;
  908.             for( f=(PrefsDirInfo*)(*dirTreeList)->First(); f; 
  909.                                     f=(PrefsDirInfo*)(*dirTreeList)->After(*f) ) 
  910.             {
  911.                 FSSpec folderSpec;
  912.                 OSErr result= FSMakeFSSpec(f->fVol,f->fDir,kODNULL, &folderSpec);
  913.                 if( !result )
  914.                     {    
  915.                         LOG("•• RegisterFileLibs in LoadCachedDirList\n");
  916.                         result= RegisterFileLibs(&folderSpec);
  917.                     }
  918. #if ODDebug
  919.                 if( result == noErr)
  920.                 {
  921.                     LOG("Registered folder (%hd,%ld,%s)\n",f->fVol,f->fDir, p2cstr(folderSpec.name));
  922.                 }
  923.                 else if( result != fragDupRegLibName && result != fragLibNotFound )
  924.                     WARN("Err %hd registering lib folder (%hd,%ld)",
  925.                             result,f->fVol,f->fDir);
  926. #endif
  927.             }
  928.         }
  929.  
  930.     }CATCH_ALL{
  931.         cacheIsValid = kODFalse;
  932.         cacheFile->Close();
  933.     }ENDTRY
  934.     
  935.     
  936.     return cacheIsValid;
  937.     
  938. }
  939.  
  940. //------------------------------------------------------------------------------
  941. // Preferences::GetCacheFile
  942. //------------------------------------------------------------------------------
  943.  
  944. ODBoolean Preferences::GetCacheFile(PlatformFile** cacheFile, ODSShort fldrVRefNum, 
  945.                                 ODSLong fldrDirID, ODULong fldrModDate )
  946. {
  947.     ODBoolean    cacheFileFound = kODFalse;
  948.     FSSpec        cacheFileSpec;
  949.     
  950.     //Construct an FSSpec
  951.     OSErr result = FSMakeFSSpec(fldrVRefNum, fldrDirID, kODCacheFileName, &cacheFileSpec);
  952.     (*cacheFile)->Specify(&cacheFileSpec);
  953.  
  954.     if (result == noErr)
  955.         cacheFileFound =  kODTrue;
  956.     else
  957.     {
  958.         ODSShort        prefVol;
  959.         ODSLong            prefDir;
  960.         FSSpec            prefCacheFileSpec;
  961.         
  962.         // check prefs folder for a cache file
  963.         if (GetODPrefsFolder( &prefVol, &prefDir ))
  964.         {
  965.             Str255 cacheName;
  966.             result = ConstructCacheFileName( fldrVRefNum, 
  967.                             fldrDirID, fldrModDate, &cacheName );
  968.             if (result == noErr)
  969.                 result = FSMakeFSSpec(prefVol, prefDir, cacheName, &prefCacheFileSpec);
  970.             if (result == noErr )
  971.             {
  972.                 (*cacheFile)->Specify(&prefCacheFileSpec);
  973.                 cacheFileFound =  kODTrue;
  974.             }
  975.         }
  976.     }
  977.  
  978.     return cacheFileFound;
  979. }
  980.  
  981. //------------------------------------------------------------------------------
  982. // Preferences::LoadCachedRezData
  983. //------------------------------------------------------------------------------
  984.  
  985. #define OFFSET(PTR,AMT)        ((void*)( (char*)(PTR)+(AMT) ))
  986.  
  987. #if PRAGMA_ALIGN_SUPPORTED
  988. #pragma options align=mac68k
  989. #endif
  990.  
  991. struct FileLoc {        // File info stored in cache file
  992.     long parID;
  993.     ODSize nameLen;
  994.     char name[64];
  995. };
  996.  
  997. #if PRAGMA_ALIGN_SUPPORTED
  998. #pragma options align=reset
  999. #endif
  1000.  
  1001. ODBoolean Preferences::LoadCachedRezData(PlatformFile* cacheFile, ODSShort vRefNum)
  1002. {
  1003.     ODBoolean     validCacheFile = kODTrue;
  1004.         
  1005.     if (cacheFile)
  1006.         TRY{
  1007.             ODSize size = cacheFile->GetEndOfFile() - cacheFile->GetFilePos();
  1008.             TempODPtr buf = ODNewPtr(size);
  1009.             cacheFile->Read(buf,(ODSLong*)&size);
  1010.             
  1011.             //LOG("size:\t%d\n",size);
  1012.             
  1013.             const void* pos = buf;
  1014.             const void* const end = OFFSET(pos,size);
  1015.             while( pos<end ) {
  1016.                 // Read dir ID & filename:
  1017.                 const FileLoc *data = (const FileLoc*)pos;
  1018.                 pos = OFFSET(pos, sizeof(long) + sizeof(long) + data->nameLen);
  1019.                 if( data->nameLen<1 || data->nameLen>63 || pos>end )
  1020.                     THROW(kODErrValueOutOfRange);
  1021.                 
  1022.                 // Construct FSSpec from same:
  1023.                 FSSpec spec;
  1024.                 spec.vRefNum = vRefNum;
  1025.                 spec.parID = data->parID;
  1026.                 spec.name[0] = data->nameLen;
  1027.                 ODBlockMove(data->name,&spec.name[1],data->nameLen);
  1028.                 
  1029.                 // Read size of 'nmap' buffer:
  1030.                 size = *(ODSize*)pos;
  1031.                 pos = OFFSET(pos,sizeof(ODSize));
  1032.                 if( pos>end || pos<(void*)buf )
  1033.                     THROW(kODErrValueOutOfRange);
  1034.                 
  1035.                 // Process the 'nmap' data:
  1036.                 Read_nmap_Buffer(pos,size,&spec,kODTrue);
  1037.                 pos = OFFSET(pos,size);
  1038.             }
  1039.             
  1040.         }CATCH_ALL{
  1041.             WARN("Error %d reading nmap cache on volume %hd",ErrorCode(),vRefNum);
  1042.             if( ErrorCode() != kODErrOutOfMemory ) {
  1043.                 cacheFile->SetEndOfFile(0);
  1044.                 validCacheFile = kODFalse;
  1045.             }
  1046.             // don't propagate exception
  1047.     }ENDTRY
  1048.     return validCacheFile;
  1049. }
  1050.  
  1051. //------------------------------------------------------------------------------
  1052. // Preferences::TraverseDirectory
  1053. //------------------------------------------------------------------------------
  1054.  
  1055. void Preferences::TraverseDirectory( ODSShort fldrVRefNum, ODSLong fldrDirID, 
  1056.                                         ODSShort depth, LinkedList* dirList )
  1057. {
  1058.     CInfoPBRec        pb;
  1059.     FSSpec            fileSpec;
  1060.     ODError            result;
  1061.  
  1062.         //check that this is not a bogus folder
  1063.     if (fldrDirID == -1)
  1064.         return;
  1065.     
  1066.         // Loop through all the files in folder
  1067.     memset (&pb,0,sizeof(pb));
  1068.     for( pb.hFileInfo.ioFDirIndex = 1; kODTrue; pb.hFileInfo.ioFDirIndex++ )
  1069.     {
  1070.         CheckCancelScanningDialog();
  1071.             //need to do this each time since PBGetCatInfo call returns val here
  1072.         pb.hFileInfo.ioNamePtr = (StringPtr)&fileSpec.name;
  1073.         pb.hFileInfo.ioVRefNum = fldrVRefNum;
  1074.         pb.hFileInfo.ioDirID = fldrDirID;  
  1075.         
  1076.         if( PBGetCatInfoSync( &pb ) != noErr )
  1077.             break;
  1078.         
  1079.         if ( (pb.dirInfo.ioFlAttrib & (1<<4)) ) 
  1080.         {
  1081.             // if this is a folder, append it to the list:
  1082.             this->AddDirInfo(dirList, fldrVRefNum, pb.dirInfo.ioDrDirID,
  1083.                                          pb.dirInfo.ioDrMdDat,depth+1, kNestedFolder );
  1084.         }
  1085.         else 
  1086.         {
  1087.             Boolean    wasAliased = kODFalse;
  1088.             fileSpec.vRefNum = pb.hFileInfo.ioVRefNum;
  1089.             fileSpec.parID = pb.hFileInfo.ioFlParID;
  1090.             
  1091.             if ( (pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) )
  1092.             {
  1093.                 FSSpec    theSpec;
  1094.                 Boolean    targetIsFolder = kODFalse;
  1095.                 
  1096.                 result = FSMakeFSSpec(fileSpec.vRefNum, fileSpec.parID,
  1097.                         fileSpec.name, &theSpec);
  1098.                 if (result == noErr)
  1099.                 {
  1100.                         //resolve alias
  1101.                     result = ResolveLocalAliasFile(&theSpec, kODTrue, &targetIsFolder, &wasAliased);
  1102.                     if ((result == noErr) && targetIsFolder && (theSpec.vRefNum == fldrVRefNum))
  1103.                     {
  1104.                         ODULong modDate;
  1105.                         long dirID = GetFldrDirID(theSpec,&modDate);
  1106.                         this->AddDirInfo(dirList, theSpec.vRefNum, dirID, modDate, depth+1, kNestedFolder);
  1107.                     }
  1108.                 }
  1109.             }
  1110.             
  1111.         }
  1112.     }
  1113. }
  1114.  
  1115.  
  1116. //------------------------------------------------------------------------------
  1117. // Preferences::ScanDirectory
  1118. //------------------------------------------------------------------------------
  1119.  
  1120. void Preferences::ScanDirectory( ODSShort fldrVRefNum, ODSLong fldrDirID, 
  1121.                                                        PlatformFile* cacheFile,
  1122.                                                        AEDesc* aetes )
  1123. {
  1124.     CInfoPBRec        pb;
  1125.     FSSpec            fileSpec;
  1126.     ODBoolean        anyEditors = kODFalse;
  1127.     ODError            result;
  1128.  
  1129.         //check that this is not a bogus folder
  1130.     if (fldrDirID == -1)
  1131.         return;
  1132.     
  1133.     FSSpec folderSpec;
  1134.     
  1135.     FSSpec tempFolderSpec;
  1136.     result= FSMakeFSSpec(fldrVRefNum,fldrDirID,kODNULL, &tempFolderSpec);
  1137.  
  1138.     LOG("Scanning folder (%hd,%ld,%s) for editors...\n", fldrVRefNum,fldrDirID, p2cstr(tempFolderSpec.name));
  1139.  
  1140.     ODSShort saveCurRefNum = CurResFile();
  1141.     
  1142.         // Loop through all the files in folder
  1143.     memset (&pb,0,sizeof(pb));
  1144.     for( pb.hFileInfo.ioFDirIndex = 1; kODTrue; pb.hFileInfo.ioFDirIndex++ )
  1145.     {
  1146.             //need to do this each time since PBGetCatInfo call returns val here
  1147.         pb.hFileInfo.ioNamePtr = (StringPtr)&fileSpec.name;
  1148.         pb.hFileInfo.ioVRefNum = fldrVRefNum;
  1149.         pb.hFileInfo.ioDirID = fldrDirID;  
  1150.         
  1151.         if( PBGetCatInfoSync( &pb ) != noErr )
  1152.             break;
  1153.         
  1154.         Boolean    wasAliased = kODFalse;
  1155.         fileSpec.vRefNum = pb.hFileInfo.ioVRefNum;
  1156.         fileSpec.parID = pb.hFileInfo.ioFlParID;
  1157.         
  1158.         if ( (pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) )
  1159.         {
  1160.             FSSpec    theSpec;
  1161.             Boolean    targetIsFolder = kODFalse;
  1162.             
  1163.             CheckCancelScanningDialog();
  1164.             result = FSMakeFSSpec(fileSpec.vRefNum, fileSpec.parID,
  1165.                     fileSpec.name, &theSpec);
  1166.             if (result == noErr)
  1167.             {
  1168.                     //resolve alias
  1169.                 result = ResolveLocalAliasFile(&theSpec, kODTrue, &targetIsFolder, &wasAliased);
  1170.                 ODBoolean throwItAway = kODFalse;
  1171.                 if (result == noErr)
  1172.                 {
  1173.                     if (theSpec.vRefNum == fldrVRefNum)
  1174.                     {
  1175.                         if (!targetIsFolder) 
  1176.                         {
  1177.                             if ( pb.hFileInfo.ioFlFndrInfo.fdType == kCFragLibraryFileType ||
  1178.                                 pb.hFileInfo.ioFlFndrInfo.fdType == kODSpecialEditorType) 
  1179.                             {
  1180.                                 // Use the original file of the alias:
  1181.                                 wasAliased = kODTrue;
  1182.                                 fileSpec.vRefNum = theSpec.vRefNum;
  1183.                                 fileSpec.parID = theSpec.parID;
  1184.                                 CopyPascalString(fileSpec.name, theSpec.name);
  1185.                             }
  1186.                         }
  1187.                     }
  1188.                     else
  1189.                         throwItAway = kODTrue;
  1190.                 }
  1191.                 else if (result == nsvErr) // no such volume or server volume
  1192.                     throwItAway = kODTrue;
  1193.             if (throwItAway)
  1194.                 {
  1195.                     // Aliases to targets on other volumes not allowed!!!
  1196.                     // need to alert user!
  1197.                     if ( targetIsFolder || pb.hFileInfo.ioFlFndrInfo.fdType == kCFragLibraryFileType ||
  1198.                         pb.hFileInfo.ioFlFndrInfo.fdType == kODSpecialEditorType) {
  1199.                         MoveToTrash(fileSpec.vRefNum, fileSpec.parID, fileSpec.name);
  1200.                         fFoundBadAlias = kODTrue;
  1201.                     }
  1202.                 }
  1203.             }
  1204.         }
  1205.         
  1206.         if ( pb.hFileInfo.ioFlFndrInfo.fdType == kCFragLibraryFileType ||
  1207.         pb.hFileInfo.ioFlFndrInfo.fdType == kODSpecialEditorType) 
  1208.         {
  1209.             ODBoolean readNMaps = kODFalse;
  1210.             short thisFile = HOpenResFile(fileSpec.vRefNum, fileSpec.parID,
  1211.                     fileSpec.name, fsRdPerm );
  1212.             if (thisFile != -1)
  1213.             {
  1214.                 ODBoolean loadable = LoadableLibrary(thisFile);
  1215.                 // Neither of these routines will throw out of themselves
  1216.                 readNMaps =  Read_nmap_Resources(&fileSpec, cacheFile, loadable);
  1217.                 if (readNMaps && loadable)
  1218.                     Read_aete_Resources(&fileSpec, aetes);
  1219.                 CloseResFile(thisFile);
  1220.             }
  1221.                 
  1222.             if( (!anyEditors || wasAliased) && 
  1223.             pb.hFileInfo.ioFlFndrInfo.fdType == kCFragLibraryFileType) {
  1224.                 // There are editors in this folder of type kCFragLibraryFileType, so register the folder later:
  1225.                 // We make the folderSpec and register when we are done with scanning this directory
  1226.                 result= FSMakeFSSpec(fldrVRefNum,fldrDirID,kODNULL, &folderSpec);
  1227.                 if( !wasAliased && !result )
  1228.                     anyEditors = kODTrue;
  1229.             }
  1230.         }
  1231.     }
  1232.     
  1233.     if (anyEditors)
  1234.     {
  1235.         // If we have any editor, then we should register the folder.
  1236.         // The reason we want to do this after the scanning is that RegisterFileLibs may try unnecessary
  1237.         // mount some servers, but if we wait until the scanning is over, then we would have move those
  1238.         // aliases to trash already so there won't be any unnecessary mounting
  1239.         result= FSMakeFSSpec(fldrVRefNum,fldrDirID,kODNULL, &folderSpec);
  1240.         if( !result )
  1241.             result= RegisterFileLibs(&folderSpec);
  1242. #if ODDebug
  1243.         if( result == noErr)
  1244.         {
  1245.             LOG("Registered folder (ScanDirectory) (%hd,%ld,%s)\n",fileSpec.vRefNum,fileSpec.parID,p2cstr(folderSpec.name));
  1246.         }
  1247.         else if( result != fragDupRegLibName && result != fragLibNotFound )
  1248.             WARN("Err %hd registering lib folder (%hd,%ld)",
  1249.                     result,fileSpec.vRefNum,fileSpec.parID);
  1250. #endif
  1251.     }
  1252.  
  1253.     UseResFile( saveCurRefNum );
  1254.  
  1255.     LOG("Done scanning folder (%hd,%ld)\n", fldrVRefNum,fldrDirID);
  1256. }
  1257.  
  1258.  
  1259. //------------------------------------------------------------------------------
  1260. // Preferences::FindDirInfo
  1261. //------------------------------------------------------------------------------
  1262.  
  1263. PrefsDirInfo*
  1264. Preferences::FindDirInfo( LinkedList* dirList, short vol, long dir )
  1265. {
  1266.     PrefsDirInfo *e;
  1267.     for( e=(PrefsDirInfo*)dirList->First(); e; e=(PrefsDirInfo*)dirList->After(*e) )
  1268.         if( e->fDir == dir && e->fVol == vol )
  1269.              return e;                        // Already in list, don't add again
  1270.     return kODNULL;
  1271. }
  1272.  
  1273. //------------------------------------------------------------------------------
  1274. // Preferences::AddDirInfo
  1275. //------------------------------------------------------------------------------
  1276.  
  1277. PrefsDirInfo*
  1278. Preferences::AddDirInfo( LinkedList* dirList, short vol, long dir, ODULong modDate, 
  1279.                                 ODSShort depth, PrefsDirType type )
  1280. {
  1281.     if( depth > kMaxDirDepth )
  1282.         return kODNULL;                        // Too deeply nested
  1283.     else if( this->FindDirInfo(dirList, vol,dir ) )
  1284.         return kODNULL;                        // Already in list
  1285.     else {
  1286.         LOG("  Add folder (%hd,%ld) to list.\n", vol,dir);
  1287.     
  1288.         PrefsDirInfo *info = new PrefsDirInfo;
  1289.         info->fType = type;
  1290.         info->fDepth = depth;
  1291.         info->fVol = vol;
  1292.         info->fDir = dir;
  1293.         info->fModDate = modDate;
  1294.         dirList->AddLast(info);
  1295.         return info;
  1296.     }
  1297. }
  1298.  
  1299. //------------------------------------------------------------------------------
  1300. // Preferences::AddDirList
  1301. //------------------------------------------------------------------------------
  1302.  
  1303. void Preferences::AddDirList(LinkedList* dirList)
  1304. {
  1305.     PrefsDirInfo *e;
  1306.     for( e=(PrefsDirInfo*)dirList->First(); e; e=(PrefsDirInfo*)dirList->After(*e) )
  1307.         this->AddDirInfo(fDirList, e->fVol, e->fDir, e->fModDate, e->fDepth, e->fType);
  1308. }
  1309.  
  1310. //------------------------------------------------------------------------------
  1311. // Preferences::Read_nmap_Resources
  1312. //    Utilty routine for reading NMAP resources and creating NameSpaces out of them
  1313. //------------------------------------------------------------------------------
  1314.  
  1315. ODBoolean Preferences::Read_nmap_Resources( const FSSpec *fsspec,
  1316.                                             PlatformFile* cacheFile,
  1317.                                             ODBoolean loadable )
  1318. {
  1319.     ODBoolean readNMaps = kODFalse;
  1320.  
  1321.     LOG("* Reading 'nmap's from file '%P' in (%hd,%ld)\n",fsspec->name,
  1322.             fsspec->vRefNum,fsspec->parID);
  1323.     TRY{
  1324.         ODSShort mappingCount = Count1Resources( kODNameMappings );
  1325.         for (short i=1; i<=mappingCount; i++) 
  1326.         {
  1327.             // Get the Resource
  1328.             Handle mappingPair = (Handle)ReadIndexedResourceIntoTempMem( kODNameMappings, i, kODTrue );
  1329.             
  1330.             ODError result = ResError();
  1331.             
  1332.             if ( mappingPair != nil && !result )
  1333.             {
  1334.                 ODLockHandle((ODHandle) mappingPair);
  1335.                 
  1336.                 ODSize bufferSize = ODGetHandleSize((ODHandle)mappingPair);
  1337.                 ODBoolean isEditorUserString = Read_nmap_Buffer( (ODPtr)*mappingPair, bufferSize, fsspec, loadable );
  1338.                 // if the editor is loadable, we write nmap into the cache
  1339.                 // if editor is not loadable, we just write the userstring into to "unusable" name space cache
  1340.                 if (loadable)
  1341.                     Cache_nmap(cacheFile, kODNULL, bufferSize, mappingPair, fsspec);
  1342.                 else if (isEditorUserString)
  1343.                     Cache_nmap(cacheFile, kODWrongCUPEditor, bufferSize, mappingPair, fsspec);
  1344.                 readNMaps = kODTrue;
  1345.                 
  1346.                 ReleaseResource( mappingPair );
  1347.             }
  1348.         }
  1349.     }CATCH_ALL{
  1350.         WARN("Error %ld reading nmaps for file %#s",ErrorCode(),fsspec->name);
  1351.         RERAISE;
  1352.     }ENDTRY
  1353.     return readNMaps;
  1354. }
  1355.  
  1356. //------------------------------------------------------------------------------
  1357. // Preferences::Read_nmap_Buffer
  1358. //------------------------------------------------------------------------------
  1359.  
  1360. ODBoolean Preferences::Read_nmap_Buffer(const void* buffer, ODSize bufferSize,
  1361.         const ODFileSpec* fsspec, ODBoolean loadable)
  1362. {
  1363.     ODObjectNameSpace *theNameSpace;
  1364.     ODSize            bufferPos=(ODSize)buffer;
  1365.     ODUShort        keyCount;
  1366.     ODUShort        valueType;
  1367.     ODBoolean         editorAvail = kODFalse;
  1368.     Environment*     ev = somGetGlobalEnvironment ();
  1369.     
  1370.     ODUShort nameLen = *(ODUShort*)bufferPos;
  1371.     bufferPos += sizeof(ODUShort);
  1372.  
  1373.     TRY
  1374.         TempODISOStr nameSpaceName = 
  1375.             (ODISOStr)ODNewPtrClear((ODSize)nameLen+1, kDefaultHeapID);
  1376.         ODBlockMove((ODPtr)bufferPos, (ODPtr)(ODISOStr)nameSpaceName, (ODSize)nameLen);
  1377.         bufferPos += nameLen;
  1378.  
  1379.         editorAvail = ODISOStrEqual( nameSpaceName, kODEditorUserString );
  1380.         
  1381.         /*    In general, we will get the namespace from the string read here and then pass it
  1382.             to the routine that reads the data. The exception is kODEditorPlatformKind
  1383.             which is not a real namespace, and whose entries are automatically read into
  1384.             the kODEditorKinds namespace. */
  1385.         
  1386.         if ( editorAvail && !loadable )
  1387.             {
  1388.             // it is kODEditorUserString but not loadable, put it in the unusable namespace
  1389.             theNameSpace = (ODObjectNameSpace*)(fNameSpaceMgr->HasNameSpace(ev, kODWrongCUPEditor));
  1390.             }
  1391.         else
  1392.             theNameSpace = (ODObjectNameSpace*)(fNameSpaceMgr->HasNameSpace(ev, nameSpaceName));
  1393.  
  1394.         if( ! theNameSpace && !ODISOStrEqual(nameSpaceName,kODEditorPlatformKind) )
  1395.             WARN("Unknown nmap namespace '%s'", (ODISOStr) nameSpaceName);
  1396.         else {
  1397.             keyCount = *(ODUShort*)bufferPos;
  1398.             bufferPos += sizeof(ODUShort);
  1399.             
  1400.             for(ODUShort i=1; i<= keyCount; i++)
  1401.             {
  1402.                 ODUShort keyLen = *(ODUShort*)bufferPos;
  1403.                 bufferPos += sizeof(ODUShort);
  1404.         
  1405.                 TempODISOStr key = 
  1406.                     (ODISOStr)ODNewPtrClear((ODSize)keyLen+1, kDefaultHeapID);
  1407.                 ODBlockMove((ODPtr)bufferPos, (ODPtr)(ODISOStr)key, (ODSize)keyLen);
  1408.                 bufferPos += (ODSize)keyLen;
  1409.         
  1410.                 if ( editorAvail && loadable )
  1411.                 {
  1412.                     // put it in the namespace here....
  1413.                     ODValueNameSpace* editorToFileNS = (ODValueNameSpace*)
  1414.                             (fNameSpaceMgr->HasNameSpace(ev, kODFileFromEditor));
  1415.                     if ( editorToFileNS ) {
  1416.                         ODFileSpec*     prevfsspec;
  1417.                         ODULong            valueLen;
  1418.                         if (ValueNameSpaceGetEntry( editorToFileNS, ev, key,
  1419.                                 (ODPtr*)&prevfsspec, &valueLen )) {
  1420. #if 0
  1421.                             if ((fsspec->vRefNum != prevfsspec->vRefNum) ||
  1422.                                 (fsspec->parID != prevfsspec->parID) ||
  1423.                                 (!EqualPascalStrings(fsspec->name, prevfsspec->name)))
  1424.                             {
  1425.                                 ParamText(fsspec->name, prevfsspec->name, "\p", "\p");
  1426.                                 ODDeleteObject( prevfsspec );
  1427.                                 if (AEInteractWithUser(0, kODNULL, kODNULL) == noErr)
  1428.                                     (void) ShowAlert(ev, kODEditorNmapClashAlertID, kODNULL, fSession);
  1429.                             }
  1430. #endif
  1431.                         }
  1432.                         else
  1433.                             ValueNameSpaceRegister( editorToFileNS, ev, key,
  1434.                                 (ODPtr)fsspec, sizeof(*fsspec) );
  1435.                     }
  1436.                 }
  1437.         
  1438.                 if (editorAvail || loadable)
  1439.                 {
  1440.                     valueType = *(ODUShort*)bufferPos;
  1441.                     bufferPos += sizeof(ODUShort);
  1442.             
  1443.                     switch( valueType )
  1444.                     {
  1445.                             // If the value type is international text read ODName 
  1446.                         case kODIsINTLTextID:
  1447.                             bufferPos = ExtractIText(bufferPos, fSession, 
  1448.                                                     (ODValueNameSpace*)theNameSpace, key);
  1449.                             break;
  1450.                         
  1451.                             // If the value type is an ISOStringList list read ODTypeList 
  1452.                         case kODIsAnISOStringListID:
  1453.                             bufferPos = ExtractISOStringList(bufferPos, fSession, theNameSpace, key);
  1454.                             break;
  1455.                             
  1456.                             // If the value type is an OSType read ODOSType 
  1457.                         case kODIsMacOSTypeID:
  1458.                             bufferPos = ExtractOSType(bufferPos, fSession,
  1459.                                                         (ODValueNameSpace*)theNameSpace, key);
  1460.                             break;
  1461.                             
  1462.                             // If the value type is an ISOString read ISOString 
  1463.                         case kODIsAnISOStringID:
  1464.                             bufferPos = ExtractISOString(bufferPos, fSession,
  1465.                                                          (ODValueNameSpace*)theNameSpace, key);
  1466.                             break;
  1467.                         
  1468.                             // If the value type is a Platform Type Spec read ODPlatformTypeSpec
  1469.                         case kODIsPltfmTypeSpacID:
  1470.                             bufferPos = ExtractPltfrmTypeSpac(bufferPos, fSession, key);
  1471.                             break;
  1472.                             
  1473.                             // If the value type is a file name for an AppleGuile help file
  1474.                         case kODIsHelpFileNameID:
  1475.                             bufferPos = ExtractHelpFileName(bufferPos, fSession, fsspec,
  1476.                                                         (ODValueNameSpace*)theNameSpace, key);
  1477.                             break;
  1478.                             
  1479.                         default:
  1480.                             break;
  1481.                     }
  1482.                 }
  1483.             }
  1484.         }
  1485.  
  1486.     CATCH_ALL
  1487.         WARN("Error %ld in Read_nmap_buffer",ErrorCode());
  1488.         RERAISE;
  1489.     ENDTRY
  1490.     
  1491.     return editorAvail;
  1492. }
  1493.  
  1494. //------------------------------------------------------------------------------
  1495. // Preferences::Write_nmap_Buffer
  1496. //------------------------------------------------------------------------------
  1497.  
  1498. void Preferences::Write_nmap_Buffer(ODPtr buffer, ODSize bufferSize)
  1499. {
  1500. }
  1501.  
  1502. //------------------------------------------------------------------------------
  1503. // Preferences::GetOpenDocPrefs
  1504. //------------------------------------------------------------------------------
  1505.  
  1506. void Preferences::GetOpenDocPrefs( )
  1507. {
  1508.         // attempt to locate the fPrefsFile
  1509.     if (!LocatePrefsFile() || 
  1510.         !VerifyPrefsFileVersion() || 
  1511.         !LoadPreferences())
  1512.     {
  1513.             // If any of the above fail, create the file
  1514.         if (fPrefsFile)
  1515.         {
  1516.             TRY{
  1517.                 fPrefsFile->Create(kODShellSignature, 
  1518.                                     kPreferencesFolderType, 
  1519.                                     smSystemScript );
  1520.                 fPrefsFile->CreateResFile();
  1521.                 fPrefsFile->SetPermission(fsRdWrPerm);
  1522.                 UpdatePrefsFileVersion();
  1523.             }CATCH_ALL{
  1524.                 WARN("Error %ld reading prefs file: deleting it",ErrorCode());
  1525.                 fPrefsFile->Delete();
  1526.                 fPrefsFile = kODNULL;
  1527.             }ENDTRY
  1528.         }
  1529.     }
  1530. }
  1531.  
  1532. //------------------------------------------------------------------------------
  1533. // Preferences::LocatePrefsFile
  1534. //------------------------------------------------------------------------------
  1535.  
  1536. ODBoolean Preferences::LocatePrefsFile()
  1537. {
  1538.     ODError         result;
  1539.     HParamBlockRec    theParamBlock;
  1540.     Str255            prefFileName;
  1541.     ODSShort        prefVol;
  1542.     ODSLong            prefDir;
  1543.     ODFileSpec        prefFileSpec;
  1544.     ODBoolean        retVal = kODFalse;
  1545.  
  1546.     if (!GetODPrefsFolder( &prefVol, &prefDir ))
  1547.         return kODFalse;
  1548.     
  1549.     ODGetString(prefFileName,kODPrefsFileNameStrID);
  1550.  
  1551.         //Construct an FSSpec
  1552.     result = FSMakeFSSpec(prefVol, prefDir, prefFileName, &prefFileSpec);
  1553.                     
  1554.     if (!fPrefsFile)
  1555.     {
  1556.         fPrefsFile = new PlatformFile;
  1557.         TRY{
  1558.             fPrefsFile->Specify(&prefFileSpec);
  1559.         }CATCH_ALL{
  1560.             fPrefsFile->Delete();
  1561.             fPrefsFile = kODNULL;
  1562.             return kODFalse;
  1563.         }ENDTRY
  1564.     }
  1565.  
  1566.         //try to find the file    
  1567.         // if this file does not exists return false
  1568.     if (result) return kODFalse;
  1569.         
  1570.     memset (&theParamBlock,0,sizeof(HParamBlockRec));
  1571.     theParamBlock.fileParam.ioNamePtr = (StringPtr)&prefFileName;
  1572.     theParamBlock.fileParam.ioVRefNum = prefVol;
  1573.     theParamBlock.fileParam.ioFDirIndex = 0;
  1574.     theParamBlock.fileParam.ioDirID = prefDir;
  1575.     if( PBHGetFInfoSync(&theParamBlock) == noErr )
  1576.         fPrefsModDate = theParamBlock.fileParam.ioFlMdDat;
  1577.     return kODTrue;
  1578. }
  1579.  
  1580. //------------------------------------------------------------------------------
  1581. // Preferences::VerifyPrefsFileVersion
  1582. //------------------------------------------------------------------------------
  1583.  
  1584. ODBoolean Preferences::VerifyPrefsFileVersion()
  1585. {
  1586.     ODSShort        result;
  1587.     ODSShort        saveCurRefNum;
  1588.     ODBoolean        retVal=kODFalse;
  1589.     
  1590.             //Get OpenDoc 'vers' resource
  1591.     VersRecHndl odVers;
  1592.     { CUsingLibraryResources r;
  1593.         odVers = (VersRecHndl)Get1Resource( 'vers', 1 );
  1594.         result = ResError();
  1595.         if (odVers )
  1596.             DetachResource((Handle)odVers);
  1597.     }
  1598.     
  1599.     if (odVers )
  1600.     {
  1601.             //Open the resource fork of the Prefs file
  1602.         saveCurRefNum = CurResFile();
  1603.         fPrefsFile->OpenResFile();
  1604.         
  1605.             //Attempt to read 'vers' resource from prefs file
  1606.         VersRecHndl prefVers = (VersRecHndl)Get1Resource('vers', 1);
  1607.         result = ResError();
  1608.         if (!prefVers)
  1609.         {
  1610.             TRY{
  1611.                 fPrefsFile->CloseResFile();
  1612.                 DeletePrefFile();
  1613.             }CATCH_ALL{
  1614.             }ENDTRY
  1615.         }
  1616.         else
  1617.         {
  1618.             ODULong tmp =  kODPrefsCompatiblemajorRev << 24
  1619.                         | kODPrefsCompatibleminorAndBugRev << 16                
  1620.                         | kODPrefsCompatiblestage << 8
  1621.                         | kODPrefsCompatiblenonRelRev;
  1622.  
  1623.             WASSERT( sizeof(ODULong) == sizeof((*prefVers)->numericVersion) );
  1624.             retVal = *((ODULong*)&((*prefVers)->numericVersion)) >= tmp;
  1625.             fPrefsFile->CloseResFile();
  1626.             
  1627.             if ( !retVal )
  1628.                 fPrefsFile->Delete();
  1629.         }
  1630.                 
  1631.         DisposeHandle((Handle)odVers);
  1632.         UseResFile( saveCurRefNum );
  1633.     }
  1634.  
  1635.     return retVal;
  1636. }
  1637.  
  1638. //------------------------------------------------------------------------------
  1639. // Preferences::LoadPreferences
  1640. //------------------------------------------------------------------------------
  1641.  
  1642. ODBoolean Preferences::LoadPreferences()
  1643. {
  1644.     ODULong            nameSpaceNameLength;
  1645.     ODISOStr        nameSpaceName;
  1646.     ODValueNameSpace*     theNameSpace;
  1647.     Environment*     ev = somGetGlobalEnvironment ();
  1648.     
  1649.  
  1650.         // If there is a pref file, open it
  1651.     if (fPrefsFile)
  1652.     {
  1653.         TRY{
  1654.             fPrefsFile->Open();
  1655.             
  1656.                 // Position mark to beginning of file
  1657.             fPrefsFile->SetFilePos(fsFromStart, 0);
  1658.             
  1659.             for ( ODSLong fileOffset = 0; 
  1660.                   fileOffset != fPrefsFile->GetEndOfFile(); 
  1661.                   fileOffset = fPrefsFile->GetFilePos() ) 
  1662.             {
  1663.                     // Get each "mapping"
  1664.                 nameSpaceNameLength = ReadSize(fPrefsFile, 
  1665.                                                    (ODStorageUnitView*)kODNULL);
  1666.                 nameSpaceName = (ODISOStr)ODNewPtrClear(nameSpaceNameLength+1,
  1667.                                                                 kDefaultHeapID);
  1668.                 TRY{
  1669.                     ReadBytes(fPrefsFile,
  1670.                                     (ODStorageUnitView*)kODNULL, nameSpaceName, 
  1671.                                     &nameSpaceNameLength);
  1672.                     theNameSpace = (ODValueNameSpace*)fNameSpaceMgr->HasNameSpace(ev,
  1673.                                                                         nameSpaceName);
  1674.                     // Create the namespace if it's unknown  --jpa
  1675.                     if( !theNameSpace ) {
  1676.                         WARN("Unknown namespace '%s' in prefs",nameSpaceName);
  1677.                         theNameSpace = (ODValueNameSpace*)
  1678.                                 fNameSpaceMgr->CreateNameSpace(ev,nameSpaceName,
  1679.                                                             kODNULL,kNumExpectedParts,
  1680.                                                             kODNSDataTypeODValue);
  1681.                     }
  1682.                     ValueNameSpaceReadFromFile(theNameSpace, fPrefsFile);
  1683.                         
  1684.                 }CATCH_ALL{
  1685.                     ODDisposePtr(nameSpaceName);
  1686.                     RERAISE;
  1687.                 }ENDTRY
  1688.  
  1689.                 ODDisposePtr(nameSpaceName);
  1690.             }
  1691.     
  1692.             fPrefsFile->Close();
  1693.     
  1694.         }CATCH_ALL{
  1695.             fPrefsFile->Close();
  1696.             DeletePrefFile();
  1697.             return kODFalse;
  1698.         }ENDTRY
  1699.         
  1700.         return kODTrue;
  1701.     }
  1702.     else
  1703.         return kODFalse;
  1704. }
  1705.  
  1706. //------------------------------------------------------------------------------
  1707. // Preferences::UpdatePreferences
  1708. //------------------------------------------------------------------------------
  1709.  
  1710. void Preferences::UpdatePreferences()
  1711. {
  1712.     ODValueNameSpace*    theNameSpace=kODNULL;
  1713.     ODSLong            sizeLong = sizeof(ODULong);
  1714.     Environment*     ev = somGetGlobalEnvironment ();
  1715.                 
  1716.     // If there is a pref file and it is writable, update it
  1717.     if (fPrefsFile && (!fPrefsFile->IsLocked()))
  1718.     {
  1719.             // Open the file
  1720.         fPrefsFile->Open();
  1721.         
  1722.             // Release current contents of file
  1723.         fPrefsFile->SetEndOfFile( 0 );
  1724.         
  1725.             // Position mark to beginning of file
  1726.         fPrefsFile->SetFilePos(fsFromStart, 0);
  1727.  
  1728.             // Get SysPrefEditorKinds nameSpace
  1729.         ODValueNameSpace* sysPrefEditorKindsNameSpace = (ODValueNameSpace*)
  1730.             fNameSpaceMgr->HasNameSpace( ev,
  1731.                                          kODSysPrefEditorKinds );
  1732.  
  1733.         if (sysPrefEditorKindsNameSpace != kODNULL)
  1734.         {
  1735.             TempODISOStr nsName = sysPrefEditorKindsNameSpace->GetName(ev); // ensure deletion
  1736.             ODULong nsNameLength = ODISOStrLength((ODISOStr) nsName);
  1737.  
  1738.                 // write length of name of name space to prefs
  1739.             fPrefsFile->Write( (const ODSByte*)&nsNameLength, &sizeLong );
  1740.                 // write name of name space to prefs
  1741.             fPrefsFile->Write( (const ODSByte*) (ODISOStr) nsName, (ODSLong*)&nsNameLength );
  1742.                 // write out entire namespace to prefs
  1743.             ValueNameSpaceWriteToFile( sysPrefEditorKindsNameSpace, fPrefsFile );
  1744.         }
  1745.  
  1746.             // Get SysPrefEditorCategories nameSpace
  1747.         ODValueNameSpace* sysPrefEditorCategoriesNameSpace = 
  1748.             (ODValueNameSpace*)(fNameSpaceMgr->
  1749.                                     HasNameSpace(ev, kODSysPrefEditorCategories ));
  1750.  
  1751.         if (sysPrefEditorCategoriesNameSpace != kODNULL)
  1752.         {
  1753.             TempODISOStr nsName = sysPrefEditorCategoriesNameSpace->GetName(ev); // ensure deletion
  1754.             ODULong nsNameLength = ODISOStrLength((ODISOStr) nsName);
  1755.  
  1756.                 // write length of name of name space to prefs
  1757.             fPrefsFile->Write( (const ODSByte*) &nsNameLength, &sizeLong );
  1758.                 // write name of name space to prefs
  1759.             fPrefsFile->Write( (const ODSByte*) (ODISOStr) nsName, (ODSLong*)&nsNameLength );
  1760.                 // write out entire namespace to prefs
  1761.             ValueNameSpaceWriteToFile( sysPrefEditorCategoriesNameSpace, fPrefsFile );
  1762.         }
  1763.  
  1764.             // Get SysPrefContainerSuites nameSpace
  1765.         ODValueNameSpace* containerSuiteNameSpace = (ODValueNameSpace*)
  1766.             (fNameSpaceMgr->HasNameSpace( ev, kODSysPrefContainerSuites ));
  1767.  
  1768.         if (containerSuiteNameSpace != kODNULL)
  1769.         {
  1770.             TempODISOStr nsName = containerSuiteNameSpace->GetName(ev); // ensure deletion
  1771.             ODULong nsNameLength = ODISOStrLength((ODISOStr) nsName);
  1772.  
  1773.                 // write length of name of name space to prefs
  1774.             fPrefsFile->Write( (const ODSByte*) &nsNameLength, &sizeLong );
  1775.                 // write name of name space to prefs
  1776.             fPrefsFile->Write( (const ODSByte*) (ODISOStr) nsName, (ODSLong*)&nsNameLength );
  1777.                 // write out entire namespace to prefs
  1778.             ValueNameSpaceWriteToFile( containerSuiteNameSpace, fPrefsFile );
  1779.         }
  1780.         
  1781.             // Close the file
  1782.         fPrefsFile->Close();
  1783.     }
  1784.     else
  1785.         WARN("Prefs file does not exist or is readonly");
  1786. }
  1787.  
  1788. //------------------------------------------------------------------------------
  1789. // Preferences::UpdatePrefsFileVersion
  1790. //------------------------------------------------------------------------------
  1791.  
  1792. void Preferences::UpdatePrefsFileVersion()
  1793. {
  1794.     OSErr            result;
  1795.     ODSShort        saveCurRefNum;
  1796.  
  1797.         //Get OpenDoc 'vers' resource
  1798.     ODSLong         savedRefNum;
  1799.     BeginUsingLibraryResources(savedRefNum);
  1800.  
  1801.     Handle odVers = Get1Resource( 'vers', 1 );
  1802.     result = ResError();
  1803.     if (odVers) {
  1804.         DetachResource(odVers);
  1805.         result = ResError();
  1806.     } else
  1807.         if( result==noErr ) result=resNotFound;
  1808.  
  1809.     EndUsingLibraryResources(savedRefNum);
  1810.     
  1811.     THROW_IF_ERROR(result);
  1812.     
  1813.         //Open the resource fork of the Prefs file
  1814.     saveCurRefNum = CurResFile();
  1815.     fPrefsFile->OpenResFile();
  1816.         //Write OpenDoc 'vers' resource to prefs file
  1817.     Handle prefVers = Get1Resource( 'vers', 1 );
  1818.     if (prefVers==kODNULL) {
  1819.         result= ResError();
  1820.         if( result==noErr || result==resNotFound ) {
  1821.             AddResource(odVers, 'vers', 1, "\p");
  1822.             result= ResError();
  1823.         }
  1824.         if( !result )
  1825.             odVers = kODNULL;    // It's been adopted by fPrefsFile
  1826.     } else {
  1827.         Size odSize = GetHandleSize(odVers);
  1828.         SetHandleSize(prefVers, odSize);
  1829.         result= MemError();
  1830.         if( !result ) {
  1831.             ODBlockMove(*odVers,*prefVers,odSize);
  1832.             ChangedResource(prefVers);
  1833.             result = ResError();
  1834.         }
  1835.     }
  1836.     // if we have a size resource in prev pref file, use it in new one
  1837.     if (fPrevSizeRsrc) {    
  1838.         AddResource(fPrevSizeRsrc, 'SIZE', -1, "\p");
  1839.         if( !ResError() )
  1840.             fPrevSizeRsrc = kODNULL;    // It's been adopted by fPrefsFile
  1841.     }
  1842.     fPrefsFile->CloseResFile();
  1843.     UseResFile( saveCurRefNum );
  1844.     if( odVers ) DisposeHandle( odVers );
  1845.     if( fPrevSizeRsrc ) {
  1846.         DisposeHandle( fPrevSizeRsrc );
  1847.         fPrevSizeRsrc = kODNULL;
  1848.     }
  1849.     THROW_IF_ERROR(result);
  1850. }
  1851.  
  1852. //------------------------------------------------------------------------------
  1853. // Preferences::DeletePrefFile
  1854. //------------------------------------------------------------------------------
  1855.  
  1856. void Preferences::DeletePrefFile()
  1857. {
  1858.     ODSShort        saveCurRefNum;
  1859.     
  1860.     TRY
  1861.             // Open the resource fork of the Prefs file
  1862.         saveCurRefNum = CurResFile();
  1863.         fPrefsFile->OpenResFile();
  1864.             // read its size resource for future use
  1865.         if( fPrevSizeRsrc ) DisposeHandle( fPrevSizeRsrc );
  1866.         fPrevSizeRsrc = Get1Resource( 'SIZE', -1 );
  1867.         if (fPrevSizeRsrc)
  1868.             DetachResource(fPrevSizeRsrc);
  1869.         fPrefsFile->CloseResFile();
  1870.         UseResFile( saveCurRefNum );
  1871.         fPrefsFile->Delete();
  1872.         if (AEInteractWithUser(0, kODNULL, kODNULL) == noErr)
  1873.             (void) ShowAlert(kODNULL, kODEditorPrefsDamagedAlertID, kODNULL, fSession);
  1874.     CATCH_ALL
  1875.     ENDTRY
  1876. }
  1877.  
  1878. //------------------------------------------------------------------------------
  1879. // Preferences::HaveEditorsFoldersChanged
  1880. //------------------------------------------------------------------------------
  1881.  
  1882. ODBoolean Preferences::HaveEditorsFoldersChanged()
  1883. {
  1884.     if( fScanning )
  1885.         return kODFalse;            // Skip re-entrant scans
  1886.         
  1887.     // Don't even scan folders more often than once every kMinResynchTime ticks:
  1888.     if( (ODULong)(TickCount() - fLastSynchedAt) <= kMinResynchTime )
  1889.         return kODFalse;
  1890.         
  1891.     // First find the current Editors folder in the System folder:
  1892.     FSSpec editorsSpec;
  1893.     ODULong editorsModDate;
  1894.     FindMagicFolder(kSystemFolderType,kCreateFolder,fEditorsFolderName,
  1895.                         &editorsSpec.vRefNum,&editorsSpec.parID,&editorsModDate);
  1896.  
  1897.     // Check if any of the scanned folders have had their mod date bumped or are deleted:
  1898.     ODBoolean foundSysEditorsFolder = kODFalse;
  1899.     PrefsDirInfo *f;
  1900.     for( f=(PrefsDirInfo*)fDirList->First(); f; f=(PrefsDirInfo*)fDirList->After(*f) ) {
  1901.         ODULong modDate;
  1902.         long parent;
  1903.         GetDirModDateAndParent(f->fVol,f->fDir, &modDate,&parent);
  1904.         
  1905.         if( modDate != f->fModDate )
  1906.             return kODTrue;                        // Folder's been changed
  1907.         else if( f->fType==kRootEditorsFolder ) {
  1908.             if( parent != fsRtDirID )
  1909.                 return kODTrue;                    // Root editors folder's been moved
  1910.         } else if( f->fType==kSysEditorsFolder ) {
  1911.             if( f->fDir != editorsSpec.parID )
  1912.                 return kODTrue;                    // Sys editors folder not same as current one
  1913.             foundSysEditorsFolder = kODTrue;
  1914.         }
  1915.     }
  1916.     
  1917.     // If the current sys editors folder isn't in the list, something's changed:
  1918.     if( !foundSysEditorsFolder )
  1919.         return kODTrue;
  1920.     
  1921.     // Look for each vol's Editors folder and see if it's a different folder:
  1922.     short vol;
  1923.     for( ODSShort vIndex=1; GetIndVolume(vIndex,&vol); vIndex++ )
  1924.         if( vol != 0 ) {
  1925.             TRY{
  1926.                 if( FindVolumeEditorsFolder(vol,fEditorsFolderName,&editorsSpec) ) {
  1927.                     if( !this->FindDirInfo(fDirList, vol,GetFldrDirID(editorsSpec)) )
  1928.                         return kODTrue;
  1929.                 }
  1930.             }CATCH_ALL{
  1931.                 return kODTrue;
  1932.             }ENDTRY
  1933.         }
  1934.     
  1935.     fLastSynchedAt = TickCount();                // Don't check again for another few seconds
  1936.     return kODFalse;
  1937. }
  1938.  
  1939. //------------------------------------------------------------------------------
  1940. // Preferences::ScanLibsAndEditors
  1941. //------------------------------------------------------------------------------
  1942.  
  1943. ODBoolean Preferences::ScanLibsAndEditors()
  1944. {
  1945.     /* First, check whether the Editors folders have changed. If not, do nothing.
  1946.        Also disable this routine completely if it's being called re-entrantly, by
  1947.        checking the fScanning flag. This is quite likely to happen because the
  1948.        namespace manager calls me anytime anyone asks for any of the editor name-
  1949.        spaces, which is something I do when rebuilding them. */
  1950.        
  1951.     if( ! this->HaveEditorsFoldersChanged() )
  1952.         return kODFalse;
  1953.     
  1954.     fScanning = kODTrue;
  1955.     fFoundBadAlias = kODFalse;
  1956.     
  1957.     TRY{
  1958.         FSSpec editorsSpec;
  1959.         
  1960.         // Clear out the name spaces, we're starting from scratch:
  1961.         this->ClearEditorNameSpaces();
  1962.         
  1963.         // First search all 'nmap's in the OpenDoc Libraries folder:
  1964.         this->GetOpenDoc_nmaps();
  1965.         
  1966.         if( fFoundBadAlias ) {
  1967.             // Tell user she can't put aliases to other volumes in an Library folder.
  1968.             // I've avoided using a filterProc to avoid re-entrancy problems since who
  1969.             // knows who might have triggered this scan by innocently asking for a
  1970.             // namespace? --jpa
  1971.             if (AEInteractWithUser(0, kODNULL, kODNULL) == noErr)
  1972.                 (void) ShowAlert(kODNULL, kODBadAliasInLibrariesAlertID, kODNULL, fSession);
  1973.             fFoundBadAlias = kODFalse;
  1974.         }
  1975.  
  1976.         // Search the "Editors" folder in the System folder:
  1977.         ODULong editorsModDate;
  1978.         if (FindMagicFolder(kSystemFolderType,kCreateFolder,fEditorsFolderName,
  1979.                             &editorsSpec.vRefNum,&editorsSpec.parID,&editorsModDate) == noErr)
  1980.             this->ScanDirectoryTree(editorsSpec.vRefNum,editorsSpec.parID,
  1981.                                     editorsModDate,kSysEditorsFolder);
  1982.         
  1983.         // Now for each mounted volume, find and search its "Editors" folder:
  1984.         short vol;
  1985.         for( ODSShort vIndex=1; GetIndVolume(vIndex,&vol); vIndex++ )
  1986.             if( vol != 0 ) {
  1987.                 TRY{
  1988.                         if( FindVolumeEditorsFolder(vol,fEditorsFolderName,&editorsSpec) ) {
  1989.                             ODULong modDate;
  1990.                             ODSLong dir = GetFldrDirID(editorsSpec,&modDate);
  1991.                             this->ScanDirectoryTree( vol, dir, modDate, kRootEditorsFolder );
  1992.                     }
  1993.                 }CATCH_ALL{
  1994.                     WARN("Error %ld reading root editors folder on volume %hd",ErrorCode(),vol);
  1995.                 }ENDTRY
  1996.             }
  1997.         
  1998.         fLastSynchedAt = ::TickCount();
  1999.         this->CloseScanningDialog();
  2000.         
  2001.     }CATCH_ALL{
  2002.         // We are updating the cache file and run into problem, delete it to keep it clean
  2003.         if (fCacheFile)
  2004.         {
  2005.             TRY {
  2006.                 fCacheFile->Close();
  2007.                 fCacheFile->Delete();
  2008.             }CATCH_ALL{
  2009.             }ENDTRY
  2010.         }
  2011.         this->CloseScanningDialog();
  2012.         RERAISE;
  2013.     }ENDTRY
  2014.     
  2015.     if( fFoundBadAlias ) {
  2016.         // Tell user she can't put aliases to other volumes in an Editors folder.
  2017.         // I've avoided using a filterProc to avoid re-entrancy problems since who
  2018.         // knows who might have triggered this scan by innocently asking for a
  2019.         // namespace? --jpa
  2020.         if (AEInteractWithUser(0, kODNULL, kODNULL) == noErr)
  2021.             (void) ShowAlert(kODNULL, kODBadAliasInEditorsAlertID, kODNULL, fSession);
  2022.     }
  2023.     
  2024.     return kODTrue;
  2025. }
  2026.  
  2027. //------------------------------------------------------------------------------
  2028. // Preferences::ShowScanningDialog
  2029. //------------------------------------------------------------------------------
  2030.  
  2031. void
  2032. Preferences::ShowScanningDialog(PlatformFile* cacheFile)
  2033. {
  2034.     fCacheFile = cacheFile;
  2035.     if( !fScanningDialog ) {
  2036.         fProgressPictIndex = 0;
  2037.         fSleepTime = 0;
  2038.         CUsingLibraryResources r;
  2039.         
  2040.         Environment* ev = somGetGlobalEnvironment();
  2041.         fSession->GetWindowState(ev)->DeactivateFrontWindows(ev);
  2042.  
  2043.         fScanningDialog = ::GetNewDialog(kODScanEditorsDialogID,kODNULL,(WindowPtr)-1L);
  2044.         ::ShowWindow(fScanningDialog);
  2045.         ::DrawDialog(fScanningDialog);
  2046.         ::SetCursor(&(ODQDGlobals.arrow));
  2047.         for (ODUShort i=0;i<4;i++) {
  2048.             TRY {
  2049.                 fProgresstPictHdl[i] = ODReadResource(kPICTRsrcType, kScanEditorsProgressBarID+i);
  2050.             }CATCH_ALL{
  2051.                 fProgresstPictHdl[i] = kODNULL;
  2052.             }ENDTRY
  2053.         }
  2054.         ODHandle    dummy;
  2055.         short        dummyType;
  2056.         GetDialogItem(fScanningDialog, kScanEditorsStopButton, &dummyType, &fButtonControl, &fProgressItemRect);
  2057.         GetDialogItem(fScanningDialog, kScanEditorsProgressItem, &dummyType, &dummy, &fProgressItemRect);
  2058.         fProgressItemRgn = ODNewRgn();
  2059.         if (fProgressItemRgn) {
  2060.             RectRgn(fProgressItemRgn,&fProgressItemRect);
  2061.         }
  2062.     }
  2063. }
  2064.  
  2065. //------------------------------------------------------------------------------
  2066. // Preferences::CloseScanningDialog
  2067. //------------------------------------------------------------------------------
  2068.  
  2069. void
  2070. Preferences::CloseScanningDialog( )
  2071. {
  2072.     if( fScanningDialog ) {
  2073.         CUsingLibraryResources r;
  2074.         ::DisposeDialog(fScanningDialog);
  2075.         fScanningDialog = kODNULL;
  2076.         for (ODUShort i=0;i<4;i++)
  2077.             ODDisposeHandle(fProgresstPictHdl[i]);
  2078.         ODDisposeHandle((Handle)fProgressItemRgn);
  2079.     }
  2080.     fScanning = kODFalse;
  2081.     fCacheFile = kODNULL;
  2082.     
  2083.     Environment* ev = somGetGlobalEnvironment();
  2084.     fSession->GetWindowState(ev)->ActivateFrontWindows(ev);
  2085. }
  2086.  
  2087. //------------------------------------------------------------------------------
  2088. // Preferences::CheckCancelScanningDialog
  2089. //------------------------------------------------------------------------------
  2090.  
  2091. void
  2092. Preferences::CheckCancelScanningDialog( )
  2093. {
  2094.     short        itemHit = 0;
  2095.     char        key;
  2096.     
  2097.     if( fScanningDialog ) {
  2098.         if (++fProgressPictIndex==4)
  2099.             fProgressPictIndex=0;
  2100.  
  2101.         if (fProgressItemRgn && fProgresstPictHdl[fProgressPictIndex]) {
  2102.             SetPort(fScanningDialog);        
  2103.             SetDialogItem(fScanningDialog, kScanEditorsProgressItem, itemDisable+picItem, fProgresstPictHdl[fProgressPictIndex], &fProgressItemRect);
  2104.             UpdateDialog(fScanningDialog, fProgressItemRgn);
  2105.         }
  2106.  
  2107.         EventRecord     theEvent;
  2108.         if (WaitNextEvent(mDownMask+keyDownMask+autoKeyMask+updateMask+osMask, &theEvent, fSleepTime, kODNULL)) {
  2109.             itemHit = 0;
  2110.             switch( theEvent.what )
  2111.                 {
  2112.                     case updateEvt:
  2113.                         if ((WindowPtr)theEvent.message == fScanningDialog) {
  2114.                             ::BeginUpdate(fScanningDialog);
  2115.                             ::DrawDialog(fScanningDialog);
  2116.                             ::EndUpdate(fScanningDialog);
  2117.                         }
  2118.                         else {
  2119.                             TRY{
  2120.                                 Environment* ev = somGetGlobalEnvironment ();
  2121.                                 ODDispatcher* dispatcher = fSession->GetDispatcher(ev);
  2122.                                 if (dispatcher)
  2123.                                     dispatcher->Dispatch(ev, (ODEventData*)&theEvent);
  2124.                             }CATCH_ALL{
  2125.                             }ENDTRY
  2126.                         }
  2127.                         break;
  2128.                     case osEvt:
  2129.                         if( (( theEvent.message >> 24 ) & 0x00FF)==suspendResumeMessage )
  2130.                             if (theEvent.message & resumeFlag) {
  2131.                                 fSleepTime = 0;
  2132.                                 HiliteControl((ControlHandle)fButtonControl, 0);
  2133.                             }
  2134.                             else {
  2135.                                 fSleepTime = 10;
  2136.                                 HiliteControl((ControlHandle)fButtonControl, 255);
  2137.                             }
  2138.                         break;
  2139.                     case keyDown:
  2140.                     case autoKey:
  2141.                         key = (theEvent.message & charCodeMask);
  2142.                         if ((key == 0x1B) || ((theEvent.modifiers & cmdKey) && (key == '.')))
  2143.                             itemHit = kScanEditorsStopButton;
  2144.                         else
  2145.                             SysBeep(0);
  2146.                         break;
  2147.                     case mouseDown:
  2148.                         if (IsDialogEvent(&theEvent))
  2149.                             (void) DialogSelect(&theEvent, &fScanningDialog, &itemHit);
  2150.                         else {
  2151.                             WindowPtr        theWindow;
  2152.                             short            part;
  2153.                             
  2154.                             part = FindWindow(theEvent.where, &theWindow);
  2155.                             if ((part == inDrag) && (theWindow == fScanningDialog)) {
  2156.                                 Rect bounds = ODQDGlobals.screenBits.bounds;
  2157.                                 DragWindow(theWindow,theEvent.where,&bounds);
  2158.                             }
  2159.                             else
  2160.                                 SysBeep(30);
  2161.                         }
  2162.                     default:
  2163.                         break;
  2164.                 }
  2165.             if (itemHit == kScanEditorsStopButton) {
  2166.                 long dummyTime;
  2167.                 HiliteControl((ControlHandle)fButtonControl, kControlButtonPart);
  2168.                 Delay(8, &dummyTime);    // give visual feedback to user
  2169.                 HiliteControl((ControlHandle)fButtonControl, 0);
  2170.                 if (ShowAlert(kODNULL, kODScanEditorsAlertID, kODNULL, fSession) == 1)
  2171.                     THROW(userCanceledErr);
  2172.                 else
  2173.                     itemHit = 0;
  2174.             };
  2175.         }
  2176.     }
  2177. }
  2178.  
  2179.  
  2180. void
  2181. Preferences::GetAETEs( ODSLong languageCode, AEDescList* aeteList)
  2182. {
  2183.     /*    First, make sure the cache is up to date, which should be a noop. 
  2184.      *    Then walk the Editors Folder cache files and accumulate aete resources
  2185.      *    with the proper language code and return them in the aeteList.
  2186.      */
  2187.        
  2188.     FSSpec editorsSpec;
  2189.     PlatformFile* cacheFile = kODNULL; ODVolatile(cacheFile);
  2190.  
  2191.     this->ScanLibsAndEditors();
  2192.     cacheFile = new PlatformFile;
  2193.     
  2194.     TRY
  2195.         // Search the "Editors" folder in the System folder:
  2196.         ODULong editorsModDate;
  2197.         if (FindMagicFolder(kSystemFolderType, kCreateFolder, fEditorsFolderName,
  2198.                         &editorsSpec.vRefNum, &editorsSpec.parID, &editorsModDate) == noErr)
  2199.         {
  2200.             this->GetCacheFile(&cacheFile, editorsSpec.vRefNum, editorsSpec.parID, editorsModDate);
  2201.             AddAETEs(cacheFile, languageCode, aeteList);
  2202.         }
  2203.         
  2204.         // Now for each mounted volume, find and search its "Editors" folder:
  2205.         short vol;
  2206.         for( ODSShort vIndex=1; GetIndVolume(vIndex,&vol); vIndex++ )
  2207.             if( vol != 0 ) {
  2208.                 TRY{
  2209.                     if( FindVolumeEditorsFolder(vol, fEditorsFolderName, &editorsSpec) ) {
  2210.                         ODULong modDate;
  2211.                         ODSLong dir = GetFldrDirID(editorsSpec, &modDate);
  2212.                         this->GetCacheFile(&cacheFile, vol, dir, modDate);
  2213.                         AddAETEs(cacheFile, languageCode, aeteList);
  2214.                     }
  2215.                 }CATCH_ALL{
  2216.                     WARN("Error %ld reading root editors folder on volume %hd",ErrorCode(),vol);
  2217.                 }ENDTRY
  2218.             }
  2219.     CATCH_ALL
  2220.         ODDeleteObject(cacheFile);
  2221.         RERAISE;
  2222.     ENDTRY
  2223.     ODDeleteObject(cacheFile);
  2224. }    // GetAETEs
  2225.  
  2226.  
  2227. //------------------------------------------------------------------------------
  2228. // GetPrefsFile
  2229. //------------------------------------------------------------------------------
  2230. PlatformFile* Preferences::GetPrefsFile()
  2231. {
  2232.     return fPrefsFile;
  2233. }
  2234.  
  2235. //------------------------------------------------------------------------------
  2236. // FindMagicFolder
  2237. //------------------------------------------------------------------------------
  2238. static ODError FindMagicFolder( OSType folderType, ODBoolean createFolder, 
  2239.                              ConstStr255Param folderName,
  2240.                              short *vol, long *dir, ODULong *modDate )
  2241. {
  2242.     CInfoPBRec        pb;
  2243.     memset (&pb,0,sizeof(pb));
  2244.  
  2245.     ODError err = noErr;
  2246.         
  2247.     TRY
  2248.         THROW_IF_ERROR( FindFolder(kOnSystemDisk, folderType, kDontCreateFolder, 
  2249.                                     &pb.dirInfo.ioVRefNum, &pb.dirInfo.ioDrDirID) );
  2250.         Str63 name;
  2251.         CopyPascalString(name,folderName);
  2252.         pb.dirInfo.ioNamePtr = name;
  2253.         pb.dirInfo.ioFDirIndex = 0;
  2254.         err =  PBGetCatInfoSync( &pb );
  2255.         if ( createFolder && (err == fnfErr))
  2256.         {
  2257.             ODSLong createdDirID;
  2258.             THROW_IF_ERROR(DirCreate (pb.dirInfo.ioVRefNum, pb.dirInfo.ioDrDirID, 
  2259.                                       folderName, &createdDirID));
  2260.             WARN("Missing folder generated by OpenDoc");
  2261.             pb.dirInfo.ioDrDirID = createdDirID;
  2262.             err = PBGetCatInfoSync( &pb );
  2263.         }
  2264.         THROW_IF_ERROR( err );
  2265.         
  2266.         if( pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias ) {
  2267.             FSSpec spec;
  2268.             ODBoolean targetIsFolder, wasAliased;
  2269.             FSMakeFSSpec(pb.dirInfo.ioVRefNum,pb.dirInfo.ioDrParID,name, &spec);
  2270.             THROW_IF_ERROR( ResolveAliasFile(&spec, kODTrue, &targetIsFolder, &wasAliased) );
  2271.             if( !targetIsFolder )
  2272.                 THROW(dirNFErr);
  2273.             // Now get dir ID of target folder:
  2274.             pb.dirInfo.ioNamePtr = spec.name;
  2275.             pb.dirInfo.ioFDirIndex = 0;
  2276.             pb.dirInfo.ioVRefNum = spec.vRefNum;
  2277.             pb.dirInfo.ioDrDirID = spec.parID;
  2278.             THROW_IF_ERROR( PBGetCatInfoSync( &pb ) );
  2279.         }
  2280.         
  2281.         *vol = pb.dirInfo.ioVRefNum;
  2282.         *dir = pb.dirInfo.ioDrDirID;
  2283.         *modDate = pb.dirInfo.ioDrMdDat;
  2284.     CATCH_ALL
  2285.         err = ErrorCode();
  2286.         *dir = 0;
  2287.     ENDTRY
  2288.     
  2289.     return err;
  2290. }
  2291.  
  2292. //------------------------------------------------------------------------------
  2293. // FindVolumeEditorsFolder
  2294. //------------------------------------------------------------------------------
  2295. static ODBoolean
  2296. FindVolumeEditorsFolder( short vol, ConstStr255Param localizedFolderName, FSSpec *folderSpec )
  2297. {
  2298.     // Look for the magic invisible hint file at the root, which contains the folder name:
  2299.     OSErr err;
  2300.     short fil;
  2301.     ODBoolean targetIsFolder, wasAliased;
  2302.     
  2303.     if( FSMakeFSSpec(vol,fsRtDirID,kODEditorHintFileName, folderSpec) == noErr ) {
  2304.         short fil;
  2305.         Str63 name;
  2306.         err= FSpOpenDF(folderSpec,fsRdPerm,&fil);
  2307.         if( !err ) {
  2308.             Size size = 64;
  2309.             err= FSRead(fil,&size,name);
  2310.             if( err==eofErr && size==1L+name[0] )
  2311.                 err= noErr;
  2312.             FSClose(fil);
  2313.         }
  2314.         if( !err )
  2315.             err= FSMakeFSSpec(vol,fsRtDirID,name, folderSpec);
  2316.         if( !err )
  2317.         {
  2318.             err = ResolveAliasFile(folderSpec, kODTrue, &targetIsFolder, &wasAliased);
  2319.             if( targetIsFolder )
  2320.                 return kODTrue;
  2321.         }
  2322.     }
  2323.     
  2324.     // If there's no hint file or it lied to us, look for the current localized name:
  2325.     err = FSMakeFSSpec(vol,fsRtDirID,localizedFolderName, folderSpec);
  2326.     if( !err )
  2327.     {
  2328.         err = ResolveAliasFile(folderSpec, kODTrue, &targetIsFolder, &wasAliased);
  2329.         if( !targetIsFolder )
  2330.             return kODFalse;
  2331.     }
  2332.     
  2333.     if( err != noErr )
  2334.         return kODFalse;
  2335.     
  2336.     // We've found the folder, so create or update the hint file:
  2337.     err= HCreate(vol,fsRtDirID,kODEditorHintFileName, kODShellSignature,kODEditorHintFileType);
  2338.     if( err==noErr ) {
  2339.         // After creating file, make it invisible:
  2340.         FInfo info;
  2341.         if( HGetFInfo(vol,fsRtDirID,kODEditorHintFileName,&info) == noErr ) {
  2342.             info.fdFlags |= kIsInvisible;
  2343.             HSetFInfo(vol,fsRtDirID,kODEditorHintFileName,&info);
  2344.         }
  2345.     } else if( err!=dupFNErr ) {
  2346.         WARN("Couldn't create/update hint file, err %hd",err);
  2347.         return kODTrue;
  2348.     }
  2349.     
  2350.     // Update the file:
  2351.     err= HOpen(vol,fsRtDirID,kODEditorHintFileName, fsWrPerm, &fil);
  2352.     if( !err ) {
  2353.         long size = 1+localizedFolderName[0];
  2354.         if( !err )
  2355.             err= FSWrite(fil,&size,localizedFolderName);
  2356.         if( !err )
  2357.             err= SetEOF(fil,size);
  2358.         FSClose(fil);
  2359.         FlushVol(kODNULL,vol);
  2360.     }
  2361.     if( err )
  2362.         WARN("Err %hd writing editor hint file on vol %hd",err,vol);
  2363.     return kODTrue;
  2364. }
  2365.  
  2366.  
  2367. //------------------------------------------------------------------------------
  2368. // GetIndVolume
  2369. //------------------------------------------------------------------------------
  2370. static ODBoolean
  2371. GetIndVolume( short index, short *vRefNum )
  2372. {
  2373.     // Returns false if no more volumes.
  2374.     // Returns true but with vRefNum=0 if this volume should be skipped.
  2375.     WASSERT(index>0);
  2376.     HParamBlockRec pb;
  2377.     pb.volumeParam.ioCompletion = NULL;
  2378.     pb.volumeParam.ioNamePtr = NULL;
  2379.     pb.volumeParam.ioVolIndex = index;
  2380.     
  2381.     if( PBHGetVInfoSync(&pb) != noErr )
  2382.         return kODFalse;
  2383.  
  2384. /*    ** Disabled; enable to skip AppleShare volumes **
  2385.     
  2386.     // Determine the driver refnum of the AppleShare file system driver:
  2387.     static short afpRefNum = 0;
  2388.     if( afpRefNum==0 ) {        // Happens first time called
  2389.         if( OpenDriver("\p.AFPTranslator",&afpRefNum) != noErr )
  2390.             afpRefNum = -32768;    // some bogus value
  2391.     }
  2392.     if( pb.volumeParam.ioVDRefNum==afpRefNum )
  2393.         *vRefNum = 0;            // Volume is a server: skip it
  2394.     else
  2395. */
  2396.  
  2397.     if( pb.volumeParam.ioVDrvInfo==0 )
  2398.         *vRefNum = 0;            // Volume is offline: skip it
  2399.     else
  2400.         *vRefNum = pb.volumeParam.ioVRefNum;
  2401.     return kODTrue;
  2402. }
  2403.  
  2404.  
  2405. //------------------------------------------------------------------------------
  2406. // GetFldrDirID
  2407. //------------------------------------------------------------------------------
  2408. static ODSLong
  2409. GetFldrDirID( FSSpec theFolderSpec, ODULong *modDate /*=NULL*/ )
  2410. {
  2411.     ODSLong dirID=-1;
  2412.     CInfoPBRec    theParamBlock;
  2413.     memset (&theParamBlock,0,sizeof(theParamBlock));
  2414.     theParamBlock.dirInfo.ioFDirIndex = 0;
  2415.     theParamBlock.dirInfo.ioNamePtr = theFolderSpec.name;
  2416.     theParamBlock.dirInfo.ioVRefNum = theFolderSpec.vRefNum;
  2417.     theParamBlock.dirInfo.ioDrDirID = theFolderSpec.parID;
  2418.     ODError result = PBGetCatInfoSync((CInfoPBPtr)&theParamBlock);
  2419.     if (result == noErr && (theParamBlock.hFileInfo.ioFlAttrib & (1<<4)) ) {
  2420.         dirID = theParamBlock.dirInfo.ioDrDirID;
  2421.         if( modDate )
  2422.             *modDate = theParamBlock.dirInfo.ioDrMdDat;
  2423.     }
  2424.  
  2425.     return dirID;
  2426. }
  2427.  
  2428.  
  2429. //------------------------------------------------------------------------------
  2430. // GetDirModDateAndParent
  2431. //------------------------------------------------------------------------------
  2432. static void
  2433. GetDirModDateAndParent( short vol, long dir, ODULong *modDate, long *parent )
  2434. {
  2435.     CInfoPBRec    pb;
  2436.     memset (&pb,0,sizeof(pb));
  2437.     pb.dirInfo.ioFDirIndex = -1;
  2438.     pb.dirInfo.ioNamePtr = kODNULL;
  2439.     pb.dirInfo.ioVRefNum = vol;
  2440.     pb.dirInfo.ioDrDirID = dir;
  2441.     ODError result = PBGetCatInfoSync((CInfoPBPtr)&pb);
  2442.     if( result )
  2443.         *modDate = *parent = 0;
  2444.     else {
  2445.         *modDate = pb.dirInfo.ioDrMdDat;
  2446.         *parent = pb.dirInfo.ioDrParID;
  2447.     }
  2448. }
  2449.  
  2450.  
  2451. //------------------------------------------------------------------------------
  2452. // ExtractIText
  2453. //------------------------------------------------------------------------------
  2454. static ODSize ExtractIText(ODSize bufferPos, ODSession* session, 
  2455.                                            ODValueNameSpace *theNameSpace, ODISOStr key)
  2456. {
  2457.     ODTradITextData* theODName = kODNULL;
  2458.     Environment*     ev = somGetGlobalEnvironment ();
  2459.  
  2460.     ScriptCode theScriptCode = *(ScriptCode*)bufferPos;
  2461.     bufferPos += sizeof(ScriptCode);
  2462.     
  2463.     LangCode theLangCode = *(LangCode*)bufferPos;
  2464.     bufferPos += sizeof(LangCode);
  2465.     
  2466.     ODUShort theODNameLen = *(ODUShort*)bufferPos;
  2467.     bufferPos += sizeof(ODUShort);
  2468.     
  2469.     char* theText = (char*)ODNewPtrClear(theODNameLen+1, kDefaultHeapID);
  2470.     ODBlockMove((ODPtr)bufferPos, (ODPtr)theText, theODNameLen);
  2471.     //theODName = CreateIText(theScriptCode, theLangCode, theText );
  2472.  
  2473.     theODName = CreateFlatIText(theScriptCode, theLangCode, theText, theODNameLen);
  2474.     ODDisposePtr( theText );
  2475.  
  2476.     bufferPos += theODNameLen;
  2477.     
  2478.     TRY
  2479.         if (theNameSpace->GetType(ev) != kODNSDataTypeODValue)
  2480.             THROW(kODErrInvalidNSType);
  2481.         // no need to remove a previously registered key
  2482.  
  2483.         // Do not allow editors to overwrite standard category user strings.
  2484.         ODBoolean        protectNS    = kODFalse;
  2485.         TempODISOStr    nsName         = theNameSpace->GetName(ev);
  2486.         if(ODISOStrEqual(nsName,kODCategoryUserString) )
  2487.         {
  2488.             ODName* catUserString = kODNULL;
  2489.             TempODName tempName = catUserString; // make sure IText contents are disposed.
  2490.             
  2491.             if (ValueNameSpaceGetODName(theNameSpace,ev,key,&catUserString))
  2492.             {
  2493.                 // if entry already exists in cat user string namespace, do not overwrite.
  2494.                 protectNS = kODTrue;
  2495.                 
  2496.                 #if ODDebug
  2497.                 
  2498.                 static ODBoolean alreadyWarned = kODFalse;
  2499.                 
  2500.                 // Get the right most identifier in the ISO string.
  2501.                 const char *lastcolon = strrchr(key,':');
  2502.                 
  2503.                 if (theODName->theText == kODNULL)
  2504.                 {
  2505.                     WARN("Ignored NULL cat user string. Using %s instead.",lastcolon+1);
  2506.                 }
  2507.                 else
  2508.                 {
  2509.                     if (ODISOStrNCompare(GetITextPtr(catUserString),theODName->theText,theODNameLen) != 0)
  2510.                     {
  2511.                         // Warn of attempt to overwrite an existing category user string with something different.
  2512.                         // This is not permitted. Note: we make the assumption standard category user strings
  2513.                         // are introduced by Core before any part editor user strings are read.
  2514.                         char* theText = (char*)ODNewPtrClear(theODNameLen+1, kDefaultHeapID);
  2515.                         ODBlockMove((ODPtr)theODName->theText, (ODPtr)theText, theODNameLen);
  2516.                         WARN("Ignored cat user string %s. Using %s instead.", theText, lastcolon+1);
  2517.                         ODDisposePtr( theText );
  2518.                         
  2519.                         if (!alreadyWarned)
  2520.                         {
  2521.                             WARN("* Please check your nmaps - you may not overwrite standard category user strings.");
  2522.                             alreadyWarned = kODTrue;
  2523.                         }
  2524.                     }
  2525.                 }
  2526.                 
  2527.                 #endif
  2528.             }
  2529.         }
  2530.         
  2531.             // Register the new entry with theNameSpace 
  2532.         if (!protectNS)
  2533.             ValueNameSpaceRegister(theNameSpace, ev, key, 
  2534.                 (ODPtr)theODName,theODNameLen+sizeof(ODTradITextDataHeader));
  2535.     CATCH_ALL
  2536.     ENDTRY
  2537.     
  2538.     ODDisposePtr( theODName );
  2539.  
  2540.     return (ODSize)bufferPos;
  2541. }
  2542.  
  2543. //------------------------------------------------------------------------------
  2544. // ExtractISOStringList
  2545. //------------------------------------------------------------------------------
  2546. static ODSize ExtractISOStringList(ODSize bufferPos, ODSession* session, 
  2547.                                            ODObjectNameSpace *theNameSpace, ODISOStr key)
  2548. {
  2549.     ODTypeList*        valueList = kODNULL;
  2550.     ODUShort        valueItemLen;
  2551.     ODISOStr        valueItem = kODNULL;
  2552.     ODObject*        entry = kODNULL;
  2553.     Environment*     ev = somGetGlobalEnvironment ();
  2554.  
  2555.     ODUShort    valueCount = *(ODUShort*)bufferPos;
  2556.     bufferPos += sizeof(ODUShort);
  2557.     
  2558.     valueList = session->GetStorageSystem(ev)->CreateTypeList(ev,(ODTypeList*)kODNULL);
  2559.  
  2560.     for(ODUShort j=1; j<= valueCount; j++)
  2561.     {
  2562.         valueItemLen = *(ODUShort*)bufferPos;
  2563.         bufferPos += sizeof(ODUShort);
  2564.  
  2565.         valueItem = (ODISOStr)ODNewPtrClear((ODSize)valueItemLen+1, kDefaultHeapID);
  2566.         ODBlockMove((ODPtr)bufferPos, (ODPtr)valueItem, valueItemLen);
  2567.         bufferPos += valueItemLen;
  2568.         
  2569.         valueList->AddLast( ev, (ODType)valueItem );
  2570.         ODDisposePtr((ODPtr)valueItem);
  2571.     }
  2572.     
  2573.         // Register entry with theNameSpace
  2574.     TRY
  2575.         if (theNameSpace->GetType(ev) != kODNSDataTypeODObject)
  2576.             THROW(kODErrInvalidNSType);
  2577.         
  2578.         // no need to remove a previously registered key
  2579.  
  2580.             // Register the new entry with theNameSpace 
  2581.         theNameSpace->Register( ev, key, (ODObject*)valueList );
  2582.     CATCH_ALL
  2583.         ODDeleteObject( valueList );
  2584.     ENDTRY
  2585.     
  2586.     return (ODSize)bufferPos;
  2587. }
  2588.  
  2589. //------------------------------------------------------------------------------
  2590. // ExtractOSType
  2591. //------------------------------------------------------------------------------
  2592. static ODSize ExtractOSType(ODSize bufferPos, ODSession* session, 
  2593.                                            ODValueNameSpace *theNameSpace, ODISOStr key)
  2594. {
  2595.     Environment*     ev = somGetGlobalEnvironment ();
  2596.  
  2597.     ODOSType    theODType = *(ODOSType*)bufferPos;
  2598.     bufferPos += sizeof(ODOSType);
  2599.     
  2600.         // Register entry with theNameSpace
  2601.     TRY
  2602.         if (theNameSpace->GetType(ev) != kODNSDataTypeODValue)
  2603.             THROW(kODErrInvalidNSType);
  2604.         // no need to remove a previously registered key
  2605.  
  2606.             // Register the new entry with theNameSpace 
  2607.         ValueNameSpaceRegister(theNameSpace,ev,key,&theODType, 
  2608.                                                           sizeof(ODOSType));
  2609.     CATCH_ALL
  2610.     ENDTRY
  2611.     
  2612.     return (ODSize)bufferPos;
  2613. }
  2614.  
  2615. //------------------------------------------------------------------------------
  2616. // ExtractPltfrmTypeSpac
  2617. //------------------------------------------------------------------------------
  2618. static ODSize ExtractPltfrmTypeSpac(ODSize bufferPos, ODSession* session, 
  2619.                                            ODISOStr key)
  2620. {
  2621.     ODObjectNameSpace*         edKindsNmSpc = kODNULL;
  2622.     ODObjectNameSpace*         kindCategoryNS = kODNULL;
  2623.     ODPlatformType            thePlfType;
  2624.     ODPlatformTypeSpace        thePlfTypeSpc;
  2625.     ODUShort                theCategoryLen;
  2626.     ODType                    theKind;
  2627.     ODISOStr                theCategory = kODNULL;
  2628.     ODObject*                entry = kODNULL;
  2629.     ODTypeList*                valueList = kODNULL;
  2630.     Environment*             ev = somGetGlobalEnvironment ();
  2631.  
  2632.     ODUShort valueCount = *(ODUShort*)bufferPos;
  2633.     bufferPos += sizeof(ODUShort);
  2634.     
  2635.     for(ODUShort j=1; j<= valueCount; j++)
  2636.     {
  2637.             // First read thePlfTypeSpc
  2638.         thePlfTypeSpc = *(ODPlatformTypeSpace*)bufferPos;
  2639.         bufferPos += sizeof(ODPlatformTypeSpace);
  2640.         
  2641.             // Next read thePlfType
  2642.         thePlfType = *(ODPlatformType*)bufferPos;
  2643.         bufferPos += sizeof(ODPlatformType);
  2644.         
  2645.         ODTranslation* translation = session->GetTranslation(ev);
  2646.         theKind = translation->GetISOTypeFromPlatformType(ev, thePlfType, thePlfTypeSpc);
  2647.         
  2648.             // Register entry with theNameSpace
  2649.         edKindsNmSpc = (ODObjectNameSpace*)(session->GetNameSpaceManager(ev)->
  2650.                                             HasNameSpace(ev, kODEditorKinds));
  2651.         TRY
  2652.             if (edKindsNmSpc->GetType(ev) != kODNSDataTypeODObject)
  2653.                 THROW(kODErrInvalidNSType);
  2654.                 
  2655.                 // if there is already a list registered add to end of it
  2656.             if (edKindsNmSpc->GetEntry(ev,key, (ODObject**)&valueList ))
  2657.                 valueList->AddLast( ev, theKind );
  2658.             else
  2659.             {    // else make a new list
  2660.                 valueList = session->GetStorageSystem(ev)->
  2661.                             CreateTypeList(ev, (ODTypeList*)kODNULL);
  2662.                 valueList->AddLast( ev, theKind );
  2663.  
  2664.                     // Register the new entry with edKindsNmSpc 
  2665.                 edKindsNmSpc->Register( ev, key, (ODObject*)valueList );
  2666.             }
  2667.         
  2668.             ODValueNameSpace *userStringNS = (ODValueNameSpace*)
  2669.                     (session->GetNameSpaceManager(ev)->HasNameSpace(ev, kODKindUserString));
  2670.             bufferPos = ExtractIText(bufferPos, session, userStringNS, theKind);
  2671.             
  2672.             kindCategoryNS = (ODObjectNameSpace*)(session->GetNameSpaceManager(ev)->
  2673.                                                 HasNameSpace(ev, kODKind));
  2674.         
  2675.             theCategoryLen = *(ODUShort*)bufferPos;
  2676.             bufferPos += sizeof(ODUShort);
  2677.         
  2678.             theCategory = (ODISOStr)ODNewPtrClear((ODSize)theCategoryLen+1, kDefaultHeapID);
  2679.             ODBlockMove((ODPtr)bufferPos, (ODPtr)theCategory, theCategoryLen);
  2680.             bufferPos += theCategoryLen;
  2681.         
  2682.             TRY
  2683.                 if (kindCategoryNS->GetType(ev) != kODNSDataTypeODObject)
  2684.                     THROW(kODErrInvalidNSType);
  2685.                 // if there is already a list registered add to end of it
  2686.                 if (kindCategoryNS->GetEntry(ev,theKind, (ODObject**)&valueList ))
  2687.                     valueList->AddLast( ev, theCategory );
  2688.                 else
  2689.                 {    // else make a new list
  2690.                     valueList = session->GetStorageSystem(ev)->
  2691.                                          CreateTypeList(ev, (ODTypeList*)kODNULL);
  2692.                     valueList->AddLast( ev, theCategory );
  2693.                         // Register the new entry with kindCategoryNS 
  2694.                     kindCategoryNS->Register( ev, theKind, (ODObject*)valueList );
  2695.                 }
  2696.             CATCH_ALL
  2697.             ENDTRY
  2698.  
  2699.             ODDisposePtr( theCategory );
  2700.             
  2701.         CATCH_ALL
  2702.         ENDTRY
  2703.  
  2704.         ODDisposePtr( theKind );
  2705.     }    
  2706.     
  2707.     return (ODSize)bufferPos;
  2708. }
  2709.  
  2710. //------------------------------------------------------------------------------
  2711. // ExtractISOString
  2712. //------------------------------------------------------------------------------
  2713. static ODSize ExtractISOString(ODSize bufferPos, ODSession* session, 
  2714.                                            ODValueNameSpace *theNameSpace, ODISOStr key)
  2715. {
  2716.     ODISOStr            valueItem = kODNULL;
  2717.     Environment*         ev = somGetGlobalEnvironment ();
  2718.  
  2719.     ODUShort    valueItemLen = *(ODUShort*)bufferPos;
  2720.     bufferPos += sizeof(ODUShort);
  2721.  
  2722.     valueItem = (ODISOStr)ODNewPtrClear((ODSize)valueItemLen+1, kDefaultHeapID);
  2723.     ODBlockMove((ODPtr)bufferPos, (ODPtr)valueItem, valueItemLen);
  2724.     bufferPos += valueItemLen;
  2725.  
  2726.         // Register entry with theNameSpace
  2727.     TRY
  2728.         if (theNameSpace->GetType(ev) != kODNSDataTypeODValue)
  2729.             THROW(kODErrInvalidNSType);
  2730.  
  2731.         ODNameSpaceManager *theNmSpcMgr = theNameSpace->GetNameSpaceManager(ev);
  2732.         // no need to remove a previously registered key
  2733.  
  2734.             // Register the new entry with theNameSpace 
  2735.         ValueNameSpaceRegister( theNameSpace, ev, key, (ODPtr)valueItem, 
  2736.                                                            valueItemLen+1 );
  2737.     CATCH_ALL
  2738.     ENDTRY
  2739.     
  2740.     ODDisposePtr( (ODPtr)valueItem );
  2741.     
  2742.     return (ODSize)bufferPos;
  2743. }
  2744.  
  2745. //------------------------------------------------------------------------------
  2746. // ExtractHelpFileName
  2747. //------------------------------------------------------------------------------
  2748. static ODSize ExtractHelpFileName(    ODSize bufferPos, 
  2749.                                     ODSession* session, 
  2750.                                     const ODFileSpec* libspec,
  2751.                                     ODValueNameSpace *theNameSpace, 
  2752.                                     ODISOStr editorID)
  2753. {
  2754.     Environment*     ev = somGetGlobalEnvironment ();
  2755.     ODFileSpec         fsspec;
  2756.  
  2757.         // Register entry with theNameSpace
  2758.     TRY
  2759.  
  2760.         fsspec.vRefNum = libspec->vRefNum;
  2761.         fsspec.parID = libspec->parID;
  2762.     
  2763.         ODUShort fileNameLen = *(ODUShort*)bufferPos;
  2764.         bufferPos += sizeof(ODUShort);
  2765.         fsspec.name[0] = fileNameLen;
  2766.         
  2767.         ODBlockMove((ODPtr)bufferPos, (ODPtr)&fsspec.name[1], fileNameLen);
  2768.         bufferPos += fileNameLen;
  2769.     
  2770.         if (theNameSpace->GetType(ev) != kODNSDataTypeODValue)
  2771.             THROW(kODErrInvalidNSType);
  2772.     
  2773.             // Register the new entry with theNameSpace 
  2774.         ValueNameSpaceRegister( theNameSpace, ev, editorID, 
  2775.                                                 (ODPtr)&fsspec, sizeof(fsspec));
  2776.     CATCH_ALL
  2777.     ENDTRY
  2778.         
  2779.     return (ODSize)bufferPos;
  2780. }
  2781.  
  2782. //------------------------------------------------------------------------------
  2783. // Cache_nmap
  2784. //------------------------------------------------------------------------------
  2785. static void
  2786. Cache_nmap( PlatformFile* cacheFile, ODISOStr nameSpaceName, ODSize bufferSize, Handle mappingPair,
  2787.             const FSSpec *fsspec )
  2788. {
  2789.     ODSLong    sizeofsize = sizeof( ODSize );
  2790.     ODSLong    sizeoflong = sizeof( long );
  2791.     ODSize    sizeofname = (ODSize)fsspec->name[0];
  2792.  
  2793.     if (cacheFile)
  2794.     {
  2795.         cacheFile->Write( (ODSByte*) &fsspec->parID, &sizeoflong );
  2796.         cacheFile->Write( (ODSByte*) &sizeofname, &sizeofsize );
  2797.         cacheFile->Write( (ODSByte*) &fsspec->name[1], (ODSLong*)&sizeofname );
  2798.         ODSize bufferPos=(ODSize)*mappingPair;
  2799.         if (nameSpaceName)
  2800.         {
  2801.             ODUShort nameLen = ODISOStrLength(nameSpaceName);
  2802.             ODUShort oldNameLen = *(ODUShort*)bufferPos;
  2803.             ODSize newBufferSize = bufferSize + nameLen - oldNameLen;
  2804.             bufferPos = bufferPos + oldNameLen + sizeof(ODUShort);
  2805.             bufferSize = bufferSize - oldNameLen - sizeof(ODUShort);
  2806.             cacheFile->Write( (ODSByte*) &newBufferSize, &sizeofsize );
  2807.             ODSLong    len = sizeof( ODUShort );
  2808.             cacheFile->Write( (ODSByte*) &nameLen, &len );
  2809.             len = nameLen;
  2810.             cacheFile->Write( (ODSByte*) nameSpaceName, &len );
  2811.         }
  2812.         else
  2813.             cacheFile->Write( (ODSByte*) &bufferSize, &sizeofsize );
  2814.         cacheFile->Write( (ODSByte*) bufferPos, (ODSLong*)&bufferSize );
  2815.     }
  2816. }
  2817.  
  2818. //------------------------------------------------------------------------------
  2819. // MoveToTrash
  2820. //------------------------------------------------------------------------------
  2821. static void
  2822. MoveToTrash( short vRefnum, long dirID, Str255 name )
  2823. {
  2824.     short foundVRefNum;
  2825.     long  foundDirID;
  2826.     
  2827.     if(!FindFolder(vRefnum, kTrashFolderType, kDontCreateFolder, 
  2828.                                 &foundVRefNum, &foundDirID))
  2829.     {
  2830.  
  2831.         CMovePBRec paramBlock ;
  2832.         memset( ¶mBlock, 0, sizeof(paramBlock) );
  2833.         
  2834.         paramBlock.ioNamePtr = name ;
  2835.         paramBlock.ioVRefNum = foundVRefNum ;
  2836.         paramBlock.ioNewDirID = foundDirID ;
  2837.         paramBlock.ioDirID = dirID ;
  2838.         
  2839.         (void) HDelete(foundVRefNum,foundDirID,name);     // ignore error (may not exist)
  2840.         OSErr result = PBCatMoveSync( ¶mBlock );
  2841.         if (result)
  2842.             (void) HDelete(vRefnum,dirID,name); 
  2843.     }
  2844.     else
  2845.         (void) HDelete(vRefnum,dirID,name); 
  2846. }
  2847.  
  2848.  
  2849. //------------------------------------------------------------------------------
  2850. // Read_aete_Resources
  2851. //------------------------------------------------------------------------------
  2852. static void
  2853. Read_aete_Resources( FSSpec* fsspec, AEDescList* aetes )
  2854. {
  2855.     LOG("* Reading 'aete's from file '%P' in (%hd,%ld)\n",fsspec->name,
  2856.             fsspec->vRefNum,fsspec->parID);
  2857.     TRY
  2858.         ODSShort aeteCount = Count1Resources( typeAETE );
  2859.         for (short i=1; i<=aeteCount; i++) 
  2860.         {
  2861.                 // Get the Resource
  2862.             Handle aete = Get1IndResource(typeAETE, i);
  2863.             ODError result = ResError();
  2864.             
  2865.             if ( aete != nil && !result )
  2866.             {
  2867.                 ODLockHandle((ODHandle) aete);
  2868.                 
  2869.                 ODSize bufferSize = ODGetHandleSize((ODHandle)aete);
  2870.                 THROW_IF_ERROR( AEPutPtr(aetes, 0, typeAETE, *aete, bufferSize) );
  2871.                 
  2872.                 ReleaseResource( aete );
  2873.             }
  2874.         }
  2875.     CATCH_ALL
  2876.         WARN("Error %ld reading aetes for file %#s",ErrorCode(),fsspec->name);
  2877.     ENDTRY
  2878. }
  2879.  
  2880. #if PRAGMA_ALIGN_SUPPORTED
  2881. #pragma options align=mac68k
  2882. #endif
  2883.  
  2884. struct partialAETE {
  2885.     short    version;
  2886.     short    language;
  2887.     short    script;
  2888. };
  2889.  
  2890. #if PRAGMA_ALIGN_SUPPORTED
  2891. #pragma options align=reset
  2892. #endif
  2893.  
  2894. //------------------------------------------------------------------------------
  2895. // AddAETEs
  2896. //------------------------------------------------------------------------------
  2897. static void
  2898. AddAETEs(PlatformFile* cacheFile, ODSLong languageCode, AEDescList* aeteList)
  2899. {
  2900.     ODPtr        ptr;
  2901.     ODULong        size;
  2902.     ODSLong        i, n, lang;
  2903.     AEDesc        temp;
  2904.     AEDesc        list;
  2905.     DescType    type;
  2906.     
  2907.     ptr = cacheFile->ReadResourcePtr(typeAECache, 0, &size);
  2908.     if (ptr != kODNULL)
  2909.     {
  2910.         PtrToHand(ptr, &temp.dataHandle, size);
  2911.         ODDisposePtr(ptr);
  2912.         temp.descriptorType = typeAERecord;
  2913.         THROW_IF_ERROR( AEGetKeyDesc(&temp, keyDirectObject, typeAEList, &list) );
  2914.         ODDisposeHandle(temp.dataHandle);
  2915.         temp.dataHandle = kODNULL;
  2916.         THROW_IF_ERROR( AECountItems(&list, &n) );
  2917.         for (i = 1; i <= n; i++)
  2918.         {
  2919.             THROW_IF_ERROR( AEGetNthDesc(&list, i, typeAETE, &type, &temp) );
  2920.             lang = (((**(partialAETE**)temp.dataHandle).script & 0xFF) << 8) | 
  2921.                     ((**(partialAETE**)temp.dataHandle).language & 0xFF);
  2922.             if (lang == languageCode)
  2923.                 THROW_IF_ERROR( AEPutDesc(aeteList, 0, &temp) );
  2924.             THROW_IF_ERROR( AEDisposeDesc(&temp) );
  2925.         }
  2926.         THROW_IF_ERROR( AEDisposeDesc(&list) );
  2927.     }
  2928. }
  2929.  
  2930.  
  2931. //------------------------------------------------------------------------------
  2932. // GetODPrefsFolder
  2933. //------------------------------------------------------------------------------
  2934.  
  2935. static ODBoolean GetODPrefsFolder(ODSShort* prefVol, ODSLong* prefDir )
  2936. {
  2937.     Str255            prefFolderName;
  2938.     ODULong         prefModDate;
  2939.     ODSLong            tempDir;
  2940.  
  2941.         //find preferences folder
  2942.     ODGetString(prefFolderName,kODPrefsFolderNameStrID);
  2943.  
  2944.     if (FindMagicFolder(kPreferencesFolderType,kDontCreateFolder,prefFolderName,
  2945.                             prefVol, prefDir, &prefModDate) != noErr)
  2946.     {
  2947.         FindFolder(kOnSystemDisk, kPreferencesFolderType, 
  2948.                         kDontCreateFolder, prefVol, &tempDir);
  2949.         if ( DirCreate(*prefVol, tempDir, prefFolderName, prefDir) != noErr)
  2950.             return kODFalse;
  2951.     }
  2952.     
  2953.     return kODTrue;
  2954. }
  2955.  
  2956. //------------------------------------------------------------------------------
  2957. // ConstructCacheFileName
  2958. //------------------------------------------------------------------------------
  2959.  
  2960. static OSErr ConstructCacheFileName(ODSShort fldrVRefNum, ODSLong fldrDirID, 
  2961.                                         ODULong fldrModDate, Str255* fileName )
  2962. {
  2963.     OSErr theError = noErr;
  2964.     ParamBlockRec pb;
  2965.     
  2966.     pb.volumeParam.ioNamePtr = (StringPtr)fileName;
  2967.     pb.volumeParam.ioVRefNum = fldrVRefNum;
  2968.     pb.volumeParam.ioVolIndex = 0;             /* Use vRefNum */
  2969.     theError = PBGetVInfoSync(&pb);
  2970.     if (theError == noErr)
  2971.     {
  2972.         Str255        dateString;
  2973.         IUDateString(fldrModDate, shortDate, dateString);
  2974.  
  2975.         ConcatPascalStrings( *fileName, "\p " );
  2976.         ConcatPascalStrings( *fileName, (ConstStr255Param)dateString );
  2977.     }
  2978.     return theError;
  2979. }
  2980.  
  2981. //------------------------------------------------------------------------------
  2982. // DeleteOldCacheFiles
  2983. //------------------------------------------------------------------------------
  2984.  
  2985. static void DeleteOldCacheFiles()
  2986. {
  2987.     ODSShort        prefVol;
  2988.     ODSLong            prefDir;
  2989.  
  2990.     if (GetODPrefsFolder( &prefVol, &prefDir ))
  2991.     {
  2992.         CInfoPBRec    pb;
  2993.         Str255 fileName;
  2994.         Str255 prefFileName;
  2995.         ODGetString(prefFileName,kODPrefsFileNameStrID);
  2996.  
  2997.             // Loop through all the files in folder
  2998.         memset (&pb,0,sizeof(pb));
  2999.         for( pb.hFileInfo.ioFDirIndex = 1; kODTrue; pb.hFileInfo.ioFDirIndex++ )
  3000.         {
  3001.                 //need to do this each time since PBGetCatInfo call returns val here
  3002.             pb.hFileInfo.ioNamePtr = (StringPtr)&fileName;
  3003.             pb.hFileInfo.ioVRefNum = prefVol;
  3004.             pb.hFileInfo.ioDirID = prefDir;  
  3005.             
  3006.             if( PBGetCatInfoSync( &pb ) != noErr )
  3007.                 break;
  3008.             
  3009.             if ( !(pb.dirInfo.ioFlAttrib & (1<<4)) && 
  3010.                 !(pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) &&
  3011.                 (pb.hFileInfo.ioFlFndrInfo.fdCreator == kODShellSignature) )
  3012.             {
  3013.                 if (!EqualPascalStrings(fileName, prefFileName))
  3014.                 {
  3015.                     ODULong        secs;
  3016.                     GetDateTime(&secs);
  3017.                         // if this cache file is over 30 days old, delete it
  3018.                     Str255        dateString;
  3019.                     ODULong aMonthAgo = secs - (30*24*60*60);
  3020.                     IUDateString(aMonthAgo, shortDate, dateString);
  3021.                     if (pb.hFileInfo.ioFlMdDat < aMonthAgo )
  3022.                     {
  3023.                         MoveToTrash( pb.hFileInfo.ioVRefNum, 
  3024.                                      pb.hFileInfo.ioFlParID, fileName );
  3025.                     }
  3026.                 }
  3027.             }
  3028.         }
  3029.     }
  3030. }
  3031.  
  3032.  
  3033. //------------------------------------------------------------------------------
  3034. // LoadableLibrary
  3035. //------------------------------------------------------------------------------
  3036.  
  3037. static ODBoolean LoadableLibrary(ODSShort resRefNum)
  3038. {
  3039.     ODBoolean    libIsLoadable = kODFalse;
  3040.     
  3041.  
  3042.     ODHandle cfrg = (ODHandle)Get1Resource(kCFragResourceType, kCFragResourceID);
  3043.     ODError result = ResError();
  3044.  
  3045.     if (cfrg) {
  3046.         DetachResource(cfrg);
  3047.         result = ResError();
  3048.     } else
  3049.         if( result==noErr ) result=resNotFound;
  3050.  
  3051.     if (result == noErr)
  3052.     {
  3053.         ODLockHandle( cfrg);
  3054.         
  3055.         ODSize bufferPos = (ODSize)*cfrg;
  3056.         cfragHeader theHeader;
  3057.         cfragDescriptor theDesc;
  3058.         
  3059.         ODBlockMove((ODPtr)bufferPos, (ODPtr)&theHeader, sizeof(cfragHeader));
  3060.         bufferPos += sizeof(cfragHeader);
  3061.         
  3062.         for(ODUShort i=0; i< theHeader.numFragDescs; i++)
  3063.         {
  3064.             ODBlockMove((ODPtr)bufferPos, (ODPtr)&theDesc.header, sizeof(cfragDescHeader));
  3065.             bufferPos += sizeof(cfragDescHeader);
  3066.             
  3067.             ODULong nameLen = theDesc.header.infoRecLen - sizeof(cfragDescHeader);
  3068.             ODBlockMove((ODPtr)bufferPos, (ODPtr)&theDesc.fragName, nameLen);
  3069.             bufferPos += nameLen;
  3070.             
  3071.             if (theDesc.header.arch == kCurrentCFragArch)
  3072.             {
  3073.                 libIsLoadable = kODTrue;
  3074.                 break;
  3075.             }
  3076.         }
  3077.  
  3078.         ODDisposeHandle( cfrg );
  3079.     }
  3080.     
  3081.     return libIsLoadable;
  3082. }
  3083.  
  3084. //------------------------------------------------------------------------------
  3085. // ResolveLocalAliasFile
  3086. //------------------------------------------------------------------------------
  3087.  
  3088. // This is a replacement of ResolveAliasFile that does not try to mount the servers
  3089.  
  3090. static OSErr ResolveLocalAliasFile(FSSpec *theSpec, Boolean resolveAliasChains, 
  3091.                                     Boolean *targetIsFolder, Boolean *wasAliased)
  3092. {
  3093.     OSErr             err;
  3094.     CInfoPBRec        pb;
  3095.  
  3096.     *targetIsFolder = kODFalse;
  3097.     ODUShort resolveCount = resolveAliasChains ? kMaxResolveCount : 1;
  3098.     memset (&pb,0,sizeof(pb));
  3099.     do {
  3100.         short aliasCount = 0;
  3101.         err = -1; // should be file not found
  3102.         *wasAliased = kODFalse;
  3103.         short aliasFile = FSpOpenResFile(theSpec,fsRdPerm);
  3104.         if (aliasFile != -1) {
  3105.             ODHandle aliasHandle = kODNULL;
  3106.             aliasHandle = Get1Resource(rAliasType, 0);
  3107.             if (aliasHandle) {
  3108.                 aliasCount = 1;
  3109.                 ODBoolean needsUpdate = kODFalse;
  3110.                 err = MatchAlias(theSpec, kARMNoUI+kARMSearch, (AliasHandle)aliasHandle, &aliasCount, (FSSpecArrayPtr)theSpec, &needsUpdate, kODNULL, kODNULL);
  3111.             }
  3112.             CloseResFile( aliasFile );
  3113.         }
  3114.         if (err == noErr) {
  3115.             if (aliasCount == 1) {
  3116.                 pb.hFileInfo.ioNamePtr = (StringPtr)&theSpec->name;
  3117.                 pb.hFileInfo.ioVRefNum = theSpec->vRefNum;
  3118.                 pb.hFileInfo.ioDirID = theSpec->parID;  
  3119.                 
  3120.                 if( PBGetCatInfoSync( &pb ) == noErr ) {
  3121.                     if ( (pb.dirInfo.ioFlAttrib & (1<<4)) ) {
  3122.                         // if this is a folder, we are done
  3123.                         *targetIsFolder = kODTrue;    
  3124.                     }
  3125.                     else
  3126.                         *wasAliased = (pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) ? kODTrue : kODFalse;
  3127.                 }
  3128.             }
  3129.             else
  3130.                 err = -1; // should be file not found
  3131.         }
  3132.     } while (*wasAliased & --resolveCount);
  3133.     return err;
  3134. }
  3135.  
  3136.  
  3137. //eof
  3138.